Fix reflection invoke file format issue for generic methods (#83438)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Tue, 4 Apr 2023 03:37:16 +0000 (12:37 +0900)
committerGitHub <noreply@github.com>
Tue, 4 Apr 2023 03:37:16 +0000 (12:37 +0900)
The file format that mapped reflection metadata to runtime artifacts had a limitation that required generic methods to be always instantiated over concrete types - we could not place canonical method bodies there. The limitation stemmed from the fact that the mapping table was placing a generic dictionary in it.

This switches the table to use NameAndSignature + an array of instantiation arguments.

The rest of this change is just deleting code that was working around the problem. The fixes in NativeLayoutVertexNode and NodeFactory.NativeLayout are fixing analysis holes that were exposed by our ability to be more lazy.

Also saves 0.4% on BasicWebApi, which is always nice.

14 files changed:
src/coreclr/nativeaot/Common/src/Internal/Runtime/TypeLoader/ExternalReferencesTable.cs
src/coreclr/nativeaot/System.Private.TypeLoader/src/Internal/Runtime/TypeLoader/TypeLoaderEnvironment.Metadata.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/GenericDictionaryNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NativeLayoutVertexNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.NativeLayout.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/NodeFactory.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectedMethodNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/ReflectionInvokeMapNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/RuntimeMethodHandleNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/GeneratingMetadataManager.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/MetadataManager.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/RootingHelpers.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/UsageBasedMetadataManager.cs
src/libraries/System.Linq/tests/default.rd.xml

index c78c846..dcc6167 100644 (file)
@@ -56,11 +56,6 @@ namespace Internal.Runtime.TypeLoader
             return RuntimeAugments.CreateRuntimeTypeHandle(GetIntPtrFromIndex(index));
         }
 
-        public IntPtr GetGenericDictionaryFromIndex(uint index)
-        {
-            return GetIntPtrFromIndex(index);
-        }
-
         public unsafe IntPtr GetAddressFromIndex(uint index)
         {
             if (index >= _elementsCount)
index 3ec00d4..51fd7d2 100644 (file)
@@ -897,14 +897,12 @@ namespace Internal.Runtime.TypeLoader
             public RuntimeTypeHandle _entryType;
             public IntPtr _methodEntrypoint;
             public uint _dynamicInvokeCookie;
-            public IntPtr _entryDictionary;
             public RuntimeTypeHandle[] _methodInstantiation;
 
             // Computed data
             private bool _hasEntryPoint;
             private bool _isMatchingMethodHandleAndDeclaringType;
             private MethodNameAndSignature _nameAndSignature;
-            private RuntimeTypeHandle[] _entryMethodInstantiation;
 
             public InvokeMapEntryDataEnumerator(
                 TLookupMethodInfo lookupMethodInfo,
@@ -925,10 +923,8 @@ namespace Internal.Runtime.TypeLoader
                 _dynamicInvokeCookie = 0xffffffff;
                 _hasEntryPoint = false;
                 _isMatchingMethodHandleAndDeclaringType = false;
-                _entryDictionary = IntPtr.Zero;
                 _methodInstantiation = null;
                 _nameAndSignature = null;
-                _entryMethodInstantiation = null;
             }
 
             public void GetNext(
@@ -944,10 +940,8 @@ namespace Internal.Runtime.TypeLoader
                 _entryType = default(RuntimeTypeHandle);
                 _methodEntrypoint = IntPtr.Zero;
                 _dynamicInvokeCookie = 0xffffffff;
-                _entryDictionary = IntPtr.Zero;
                 _methodInstantiation = null;
                 _nameAndSignature = null;
-                _entryMethodInstantiation = null;
 
                 // If the current entry is not a canonical entry of the same canonical form kind we are looking for, then this cannot be a match
                 if (((_flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0) != (_canonFormKind == CanonicalFormKind.Universal))
@@ -988,17 +982,18 @@ namespace Internal.Runtime.TypeLoader
                 if ((_flags & InvokeTableFlags.IsGenericMethod) == 0)
                     return;
 
-                if ((_flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0)
+                if ((_flags & InvokeTableFlags.RequiresInstArg) != 0)
                 {
-                    Debug.Assert((_hasEntryPoint || ((_flags & InvokeTableFlags.HasVirtualInvoke) != 0)) && ((_flags & InvokeTableFlags.RequiresInstArg) != 0));
+                    Debug.Assert(_hasEntryPoint || ((_flags & InvokeTableFlags.HasVirtualInvoke) != 0));
 
                     uint nameAndSigPointerToken = entryParser.GetUnsigned();
                     _nameAndSignature = TypeLoaderEnvironment.Instance.GetMethodNameAndSignatureFromNativeLayoutOffset(_moduleHandle, nameAndSigPointerToken);
                 }
-                else if (((_flags & InvokeTableFlags.RequiresInstArg) != 0) && _hasEntryPoint)
-                    _entryDictionary = extRefTable.GetGenericDictionaryFromIndex(entryParser.GetUnsigned());
-                else
+
+                if ((_flags & InvokeTableFlags.IsUniversalCanonicalEntry) == 0)
+                {
                     _methodInstantiation = GetTypeSequence(ref extRefTable, ref entryParser);
+                }
             }
 
             public bool IsMatchingOrCompatibleEntry()
@@ -1018,15 +1013,7 @@ namespace Internal.Runtime.TypeLoader
                     return true;
                 }
 
-                // Generic non-shareable method or abstract methods: check for the canonical equivalency of the method
-                // instantiation arguments that we read from the entry
-                if (((_flags & InvokeTableFlags.RequiresInstArg) == 0) || !_hasEntryPoint)
-                    return _lookupMethodInfo.CanInstantiationsShareCode(_methodInstantiation, _canonFormKind);
-
-                // Generic shareable method: check for canonical equivalency of the method instantiation arguments.
-                // The method instantiation arguments are extracted from the generic dictionary pointer that we read from the entry.
-                Debug.Assert(_entryDictionary != IntPtr.Zero);
-                return GetNameAndSignatureAndMethodInstantiation() && _lookupMethodInfo.CanInstantiationsShareCode(_entryMethodInstantiation, _canonFormKind);
+                return _lookupMethodInfo.CanInstantiationsShareCode(_methodInstantiation, _canonFormKind);
             }
 
             public bool GetMethodEntryPoint(out IntPtr methodEntrypoint, out TDictionaryComponentType dictionaryComponent, out IntPtr rawMethodEntrypoint)
@@ -1057,7 +1044,7 @@ namespace Internal.Runtime.TypeLoader
                 }
 
                 // Dictionary for generic method (either found statically or constructed dynamically)
-                return GetNameAndSignatureAndMethodInstantiation() && _lookupMethodInfo.GetMethodDictionary(_nameAndSignature, out dictionaryComponent);
+                return _lookupMethodInfo.GetMethodDictionary(_nameAndSignature, out dictionaryComponent);
             }
 
             private bool GetMethodEntryPointComponent(TDictionaryComponentType dictionaryComponent, out IntPtr methodEntrypoint)
@@ -1074,27 +1061,6 @@ namespace Internal.Runtime.TypeLoader
 
                 return true;
             }
-
-            private bool GetNameAndSignatureAndMethodInstantiation()
-            {
-                if (_nameAndSignature != null)
-                {
-                    Debug.Assert(((_flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0) || (_entryMethodInstantiation != null && _entryMethodInstantiation.Length > 0));
-                    return true;
-                }
-
-                if ((_flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0)
-                {
-                    // _nameAndSignature should have been read from the InvokeMap entry directly!
-                    Debug.Fail("Universal canonical entries do NOT have dictionary entries!");
-                    return false;
-                }
-
-                RuntimeTypeHandle dummy1;
-                bool success = TypeLoaderEnvironment.Instance.TryGetGenericMethodComponents(_entryDictionary, out dummy1, out _nameAndSignature, out _entryMethodInstantiation);
-                Debug.Assert(success && dummy1.Equals(_entryType) && _nameAndSignature != null && _entryMethodInstantiation != null && _entryMethodInstantiation.Length > 0);
-                return success;
-            }
         }
 
         public bool TryGetMetadataForTypeMethodNameAndSignature(RuntimeTypeHandle declaringTypeHandle, MethodNameAndSignature nameAndSignature, out QMethodDefinition methodHandle)
index ddc8194..3358175 100644 (file)
@@ -7,8 +7,6 @@ using System.Diagnostics;
 using Internal.Text;
 using Internal.TypeSystem;
 
-using CombinedDependencyList = System.Collections.Generic.List<ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.CombinedDependencyListEntry>;
-
 namespace ILCompiler.DependencyAnalysis
 {
     /// <summary>
@@ -198,13 +196,7 @@ namespace ILCompiler.DependencyAnalysis
         protected override TypeSystemContext Context => _owningMethod.Context;
         public override TypeSystemEntity OwningEntity => _owningMethod;
         public MethodDesc OwningMethod => _owningMethod;
-        public override bool HasConditionalStaticDependencies => true;
-        public override IEnumerable<CombinedDependencyListEntry> GetConditionalStaticDependencies(NodeFactory factory)
-        {
-            CombinedDependencyList list = null;
-            factory.MetadataManager.GetConditionalDependenciesDueToMethodGenericDictionary(ref list, factory, _owningMethod);
-            return list ?? (IEnumerable<CombinedDependencyListEntry>)System.Array.Empty<CombinedDependencyListEntry>();
-        }
+        public override bool HasConditionalStaticDependencies => false;
 
         protected override DependencyList ComputeNonRelocationBasedDependencies(NodeFactory factory)
         {
@@ -247,8 +239,6 @@ namespace ILCompiler.DependencyAnalysis
             // Make sure the dictionary can also be populated
             dependencies.Add(factory.ShadowConcreteMethod(_owningMethod), "Dictionary contents");
 
-            factory.MetadataManager.GetDependenciesForGenericDictionary(ref dependencies, factory, _owningMethod);
-
             return dependencies;
         }
 
index 6248043..a9aad56 100644 (file)
@@ -1708,6 +1708,7 @@ namespace ILCompiler.DependencyAnalysis
 
         public NativeLayoutFieldLdTokenGenericDictionarySlotNode(FieldDesc field)
         {
+            Debug.Assert(field.OwningType.IsRuntimeDeterminedSubtype);
             _field = field;
         }
 
@@ -1717,12 +1718,21 @@ namespace ILCompiler.DependencyAnalysis
 
         public sealed override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
         {
-            yield return new DependencyListEntry(factory.NativeLayout.FieldLdTokenVertex(_field), "Field Signature");
+            var result = new DependencyList
+            {
+                { factory.NativeLayout.FieldLdTokenVertex(_field), "Field Signature" }
+            };
 
             foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_field.OwningType))
             {
-                yield return new DependencyListEntry(dependency, "template construction dependency");
+                result.Add(dependency, "template construction dependency");
             }
+
+            var canonOwningType = (InstantiatedType)_field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
+            FieldDesc canonField = factory.TypeSystemContext.GetFieldForInstantiatedType(_field.GetTypicalFieldDefinition(), canonOwningType);
+            factory.MetadataManager.GetDependenciesDueToLdToken(ref result, factory, canonField);
+
+            return result;
         }
 
         protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
@@ -1747,18 +1757,25 @@ namespace ILCompiler.DependencyAnalysis
 
         public sealed override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFactory factory)
         {
-            yield return new DependencyListEntry(factory.NativeLayout.MethodLdTokenVertex(_method), "Method Signature");
+            var result = new DependencyList
+            {
+                { factory.NativeLayout.MethodLdTokenVertex(_method), "Method Signature" }
+            };
 
             foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(_method.OwningType))
             {
-                yield return new DependencyListEntry(dependency, "template construction dependency for method OwningType");
+                result.Add(dependency, "template construction dependency for method OwningType");
             }
 
             foreach (var type in _method.Instantiation)
             {
                 foreach (var dependency in factory.NativeLayout.TemplateConstructableTypes(type))
-                    yield return new DependencyListEntry(dependency, "template construction dependency for method Instantiation types");
+                    result.Add(dependency, "template construction dependency for method Instantiation types");
             }
+
+            factory.MetadataManager.GetDependenciesDueToLdToken(ref result, factory, _method.GetCanonMethodTarget(CanonicalFormKind.Specific));
+
+            return result;
         }
 
         protected sealed override Vertex WriteSignatureVertex(NativeWriter writer, NodeFactory factory)
index e1249f0..f87f133 100644 (file)
@@ -176,6 +176,8 @@ namespace ILCompiler.DependencyAnalysis
                     {
                         yield return _factory.NativeLayout.TemplateTypeLayout(arrayCanonicalType);
                     }
+
+                    yield return _factory.MaximallyConstructableType(arrayCanonicalType);
                 }
 
                 while (type.IsParameterizedType)
index 70713b3..b1111d7 100644 (file)
@@ -957,6 +957,9 @@ namespace ILCompiler.DependencyAnalysis
         private NodeCache<MethodDesc, ReflectedMethodNode> _reflectedMethods;
         public ReflectedMethodNode ReflectedMethod(MethodDesc method)
         {
+            // We track reflectability at canonical method body level
+            method = method.GetCanonMethodTarget(CanonicalFormKind.Specific);
+
             return _reflectedMethods.GetOrAdd(method);
         }
 
index 729bf52..0696fe9 100644 (file)
@@ -24,8 +24,7 @@ namespace ILCompiler.DependencyAnalysis
 
         public ReflectedMethodNode(MethodDesc method)
         {
-            Debug.Assert(!method.IsCanonicalMethod(CanonicalFormKind.Any) ||
-                method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method);
+            Debug.Assert(method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method);
             _method = method;
         }
 
@@ -53,12 +52,6 @@ namespace ILCompiler.DependencyAnalysis
                 dependencies.Add(factory.ReflectedMethod(typicalMethod), "Definition of the reflectable method");
             }
 
-            MethodDesc canonMethod = _method.GetCanonMethodTarget(CanonicalFormKind.Specific);
-            if (canonMethod != _method)
-            {
-                dependencies.Add(factory.ReflectedMethod(canonMethod), "Canonical version of the reflectable method");
-            }
-
             // Make sure we generate the method body and other artifacts.
             if (MetadataManager.IsMethodSupportedInReflectionInvoke(_method))
             {
@@ -82,11 +75,7 @@ namespace ILCompiler.DependencyAnalysis
 
                 if (!_method.IsAbstract)
                 {
-                    dependencies.Add(factory.MethodEntrypoint(canonMethod), "Body of a reflectable method");
-
-                    if (_method.HasInstantiation
-                        && _method != canonMethod)
-                        dependencies.Add(factory.MethodGenericDictionary(_method), "Dictionary of a reflectable method");
+                    dependencies.Add(factory.MethodEntrypoint(_method), "Body of a reflectable method");
                 }
             }
 
index b541f52..08c3cb9 100644 (file)
@@ -50,6 +50,7 @@ namespace ILCompiler.DependencyAnalysis
         public static void AddDependenciesDueToReflectability(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
         {
             Debug.Assert(factory.MetadataManager.IsReflectionInvokable(method));
+            Debug.Assert(method.GetCanonMethodTarget(CanonicalFormKind.Specific) == method);
 
             dependencies ??= new DependencyList();
 
@@ -101,7 +102,7 @@ namespace ILCompiler.DependencyAnalysis
             }
 
             if (method.OwningType.IsValueType && !method.Signature.IsStatic)
-                dependencies.Add(factory.ExactCallableAddress(method, isUnboxingStub: true), "Reflection unboxing stub");
+                dependencies.Add(factory.MethodEntrypoint(method, unboxingStub: true), "Reflection unboxing stub");
 
             // If the method is defined in a different module than this one, a metadata token isn't known for performing the reference
             // Use a name/sig reference instead.
@@ -113,12 +114,13 @@ namespace ILCompiler.DependencyAnalysis
 
             if (method.HasInstantiation)
             {
-                if (method.IsCanonicalMethod(CanonicalFormKind.Universal))
+                if (method.IsCanonicalMethod(CanonicalFormKind.Any))
                 {
-                    dependencies.Add(factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method)),
-                        "UniversalCanon signature of method");
+                    dependencies.Add(factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition())),
+                        "Signature of canonical method");
                 }
-                else if (!method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg() || method.IsAbstract)
+
+                if (!method.IsCanonicalMethod(CanonicalFormKind.Universal))
                 {
                     foreach (var instArg in method.Instantiation)
                     {
@@ -150,6 +152,8 @@ namespace ILCompiler.DependencyAnalysis
             {
                 MethodDesc method = mappingEntry.Entity;
 
+                Debug.Assert(method == method.GetCanonMethodTarget(CanonicalFormKind.Specific));
+
                 if (!factory.MetadataManager.ShouldMethodBeInInvokeMap(method))
                     continue;
 
@@ -158,7 +162,7 @@ namespace ILCompiler.DependencyAnalysis
                 if (method.HasInstantiation)
                     flags |= InvokeTableFlags.IsGenericMethod;
 
-                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg())
+                if (method.RequiresInstArg())
                 {
                     bool goesThroughInstantiatingUnboxingThunk = method.OwningType.IsValueType && !method.Signature.IsStatic && !method.HasInstantiation;
                     if (!goesThroughInstantiatingUnboxingThunk)
@@ -213,7 +217,7 @@ namespace ILCompiler.DependencyAnalysis
                 {
                     vertex = writer.GetTuple(vertex,
                         writer.GetUnsignedConstant(_externalReferences.GetIndex(
-                            factory.MethodEntrypoint(method.GetCanonMethodTarget(CanonicalFormKind.Specific),
+                            factory.MethodEntrypoint(method,
                             unboxingStub: method.OwningType.IsValueType && !method.Signature.IsStatic))));
                 }
 
@@ -226,12 +230,13 @@ namespace ILCompiler.DependencyAnalysis
 
                 if ((flags & InvokeTableFlags.IsGenericMethod) != 0)
                 {
-                    if ((flags & InvokeTableFlags.IsUniversalCanonicalEntry) != 0)
+                    if ((flags & InvokeTableFlags.RequiresInstArg) != 0)
                     {
-                        var nameAndSigGenericMethod = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method));
+                        var nameAndSigGenericMethod = factory.NativeLayout.PlacedSignatureVertex(factory.NativeLayout.MethodNameAndSignatureVertex(method.GetTypicalMethodDefinition()));
                         vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant((uint)nameAndSigGenericMethod.SavedVertex.VertexOffset));
                     }
-                    else if ((flags & InvokeTableFlags.RequiresInstArg) == 0 || (flags & InvokeTableFlags.HasEntrypoint) == 0)
+
+                    if ((flags & InvokeTableFlags.IsUniversalCanonicalEntry) == 0)
                     {
                         VertexSequence args = new VertexSequence();
                         for (int i = 0; i < method.Instantiation.Length; i++)
@@ -241,14 +246,9 @@ namespace ILCompiler.DependencyAnalysis
                         }
                         vertex = writer.GetTuple(vertex, args);
                     }
-                    else
-                    {
-                        uint dictionaryId = _externalReferences.GetIndex(factory.MethodGenericDictionary(method));
-                        vertex = writer.GetTuple(vertex, writer.GetUnsignedConstant(dictionaryId));
-                    }
                 }
 
-                int hashCode = method.GetCanonMethodTarget(CanonicalFormKind.Specific).OwningType.GetHashCode();
+                int hashCode = method.OwningType.GetHashCode();
                 typeMapHashTable.Append((uint)hashCode, hashTableSection.Place(vertex));
             }
 
index c01ba9e..eab08b1 100644 (file)
@@ -52,12 +52,13 @@ namespace ILCompiler.DependencyAnalysis
                 && _targetMethod.HasInstantiation && _targetMethod.IsVirtual)
             {
                 dependencies ??= new DependencyList();
-                dependencies.Add(factory.GVMDependencies(_targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific)), "GVM dependencies for runtime method handle");
+                MethodDesc canonMethod = _targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
+                dependencies.Add(factory.GVMDependencies(canonMethod), "GVM dependencies for runtime method handle");
 
                 // GVM analysis happens on canonical forms, but this is potentially injecting new genericness
                 // into the system. Ensure reflection analysis can still see this.
                 if (_targetMethod.IsAbstract)
-                    factory.MetadataManager.GetDependenciesDueToMethodCodePresence(ref dependencies, factory, _targetMethod, methodIL: null);
+                    factory.MetadataManager.GetDependenciesDueToMethodCodePresence(ref dependencies, factory, canonMethod, methodIL: null);
             }
 
             factory.MetadataManager.GetDependenciesDueToLdToken(ref dependencies, factory, _targetMethod);
index 381a81b..14f1bdf 100644 (file)
@@ -131,7 +131,6 @@ namespace ILCompiler
                     typeMappings.Add(new MetadataMapping<MetadataType>(definition, writer.GetRecordHandle(record)));
             }
 
-            HashSet<MethodDesc> canonicalGenericMethods = new HashSet<MethodDesc>();
             foreach (var method in GetReflectableMethods())
             {
                 if (method.IsGenericMethodDefinition || method.OwningType.IsGenericDefinition)
@@ -140,11 +139,9 @@ namespace ILCompiler
                     continue;
                 }
 
-                if ((method.HasInstantiation && method.IsCanonicalMethod(CanonicalFormKind.Specific))
-                    || (!method.HasInstantiation && method.GetCanonMethodTarget(CanonicalFormKind.Specific) != method))
+                if (method.GetCanonMethodTarget(CanonicalFormKind.Specific) != method)
                 {
-                    // Methods that are not in their canonical form are not interesting with the exception
-                    // of generic methods: their dictionaries convey their identity.
+                    // Methods that are not in their canonical form are not interesting
                     continue;
                 }
 
@@ -154,10 +151,6 @@ namespace ILCompiler
                 if ((GetMetadataCategory(method) & MetadataCategory.RuntimeMapping) == 0)
                     continue;
 
-                // If we already added a canonically equivalent generic method, skip this one.
-                if (method.HasInstantiation && !canonicalGenericMethods.Add(method.GetCanonMethodTarget(CanonicalFormKind.Specific)))
-                    continue;
-
                 MetadataRecord record = transformed.GetTransformedMethodDefinition(method.GetTypicalMethodDefinition());
 
                 if (record != null)
@@ -168,19 +161,16 @@ namespace ILCompiler
             foreach (var field in GetFieldsWithRuntimeMapping())
             {
                 FieldDesc fieldToAdd = field;
-                if (!field.IsStatic)
+                TypeDesc canonOwningType = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
+                if (canonOwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
                 {
-                    TypeDesc canonOwningType = field.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific);
-                    if (canonOwningType != field.OwningType)
-                    {
-                        FieldDesc canonField = _typeSystemContext.GetFieldForInstantiatedType(field.GetTypicalFieldDefinition(), (InstantiatedType)canonOwningType);
+                    FieldDesc canonField = _typeSystemContext.GetFieldForInstantiatedType(field.GetTypicalFieldDefinition(), (InstantiatedType)canonOwningType);
 
-                        // If we already added a canonically equivalent field, skip this one.
-                        if (!canonicalFields.Add(canonField))
-                            continue;
+                    // If we already added a canonically equivalent field, skip this one.
+                    if (!canonicalFields.Add(canonField))
+                        continue;
 
-                        fieldToAdd = canonField;
-                    }
+                    fieldToAdd = canonField;
                 }
 
                 Field record = transformed.GetTransformedFieldDefinition(fieldToAdd.GetTypicalFieldDefinition());
index f848eb3..6f06532 100644 (file)
@@ -257,9 +257,6 @@ namespace ILCompiler
             if (dictionaryNode != null)
             {
                 _genericDictionariesGenerated.Add(dictionaryNode);
-
-                if (dictionaryNode.OwningEntity is MethodDesc method && AllMethodsCanBeReflectable)
-                    _reflectableMethods.Add(method);
             }
 
             if (obj is InterfaceDispatchCellNode dispatchCell)
@@ -531,12 +528,6 @@ namespace ILCompiler
             GetDependenciesDueToMethodCodePresenceInternal(ref dependencies, factory, method, methodIL);
         }
 
-        public virtual void GetConditionalDependenciesDueToMethodGenericDictionary(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method)
-        {
-            // MetadataManagers can override this to provide additional dependencies caused by the presence of
-            // method generic dictionary.
-        }
-
         public virtual void GetConditionalDependenciesDueToMethodCodePresence(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method)
         {
             // MetadataManagers can override this to provide additional dependencies caused by the presence of
@@ -903,10 +894,6 @@ namespace ILCompiler
             return null;
         }
 
-        public virtual void GetDependenciesForGenericDictionary(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
-        {
-        }
-
         public virtual void NoteOverridingMethod(MethodDesc baseMethod, MethodDesc overridingMethod)
         {
         }
index 61b43a2..2e72c95 100644 (file)
@@ -28,20 +28,14 @@ namespace ILCompiler
         {
             rootProvider.AddReflectionRoot(type, reason);
 
-            InstantiatedType fallbackNonCanonicalOwningType = null;
-
             // Instantiate generic types over something that will be useful at runtime
             if (type.IsGenericDefinition)
             {
-                Instantiation canonInst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: true);
-                if (canonInst.IsNull)
+                Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: true);
+                if (inst.IsNull)
                     return;
 
-                Instantiation concreteInst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false);
-                if (!concreteInst.IsNull)
-                    fallbackNonCanonicalOwningType = ((MetadataType)type).MakeInstantiatedType(concreteInst);
-
-                type = ((MetadataType)type).MakeInstantiatedType(canonInst);
+                type = ((MetadataType)type).MakeInstantiatedType(inst);
 
                 rootProvider.AddReflectionRoot(type, reason);
             }
@@ -57,30 +51,15 @@ namespace ILCompiler
 
             if (type.IsDefType)
             {
-                foreach (var method in type.GetMethods())
+                foreach (var method in type.ConvertToCanonForm(CanonicalFormKind.Specific).GetMethods())
                 {
                     if (method.HasInstantiation)
                     {
-                        // Make a non-canonical instantiation.
-                        // We currently have a file format limitation that requires generic methods to be concrete.
-                        // A rooted canonical method body is not visible to the reflection mapping tables.
-                        Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: false);
-
+                        Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: true);
                         if (inst.IsNull)
-                        {
-                            // Can't root anything useful
-                        }
-                        else if (!method.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
-                        {
-                            // Owning type is not canonical, can use the instantiation directly.
-                            TryRootMethod(rootProvider, method.MakeInstantiatedMethod(inst), reason);
-                        }
-                        else if (fallbackNonCanonicalOwningType != null)
-                        {
-                            // We have a fallback non-canonical type we can root a body on
-                            MethodDesc alternateMethod = method.Context.GetMethodForInstantiatedType(method.GetTypicalMethodDefinition(), fallbackNonCanonicalOwningType);
-                            TryRootMethod(rootProvider, alternateMethod.MakeInstantiatedMethod(inst), reason);
-                        }
+                            continue;
+
+                        TryRootMethod(rootProvider, method.MakeInstantiatedMethod(inst), reason);
                     }
                     else
                     {
@@ -172,7 +151,7 @@ namespace ILCompiler
             if (method.OwningType.IsGenericDefinition || method.OwningType.ContainsSignatureVariables(treatGenericParameterLikeSignatureVariable: true))
             {
                 TypeDesc owningType = method.OwningType.GetTypeDefinition();
-                Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(owningType.Instantiation, allowCanon: !method.HasInstantiation);
+                Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(owningType.Instantiation, allowCanon: true);
                 if (inst.IsNull)
                 {
                     return false;
@@ -187,7 +166,7 @@ namespace ILCompiler
             {
                 method = method.GetMethodDefinition();
 
-                Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: false);
+                Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(method.Instantiation, allowCanon: true);
                 if (inst.IsNull)
                 {
                     return false;
index 5403534..bfb48d1 100644 (file)
@@ -137,12 +137,9 @@ namespace ILCompiler
             if (reflectedFieldNode != null)
             {
                 FieldDesc field = reflectedFieldNode.Field;
-                DefType fieldOwningType = field.OwningType;
 
                 // Filter out to those that make sense to have in the mapping tables
-                if (!fieldOwningType.IsGenericDefinition
-                    && !field.IsLiteral
-                    && (!fieldOwningType.IsCanonicalSubtype(CanonicalFormKind.Specific) || !field.IsStatic))
+                if (!field.OwningType.IsGenericDefinition && !field.IsLiteral)
                 {
                     Debug.Assert((GetMetadataCategory(field) & MetadataCategory.RuntimeMapping) != 0);
                     _fieldsWithRuntimeMapping.Add(field);
@@ -577,26 +574,6 @@ namespace ILCompiler
             }
         }
 
-        public override void GetConditionalDependenciesDueToMethodGenericDictionary(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method)
-        {
-            Debug.Assert(!method.IsSharedByGenericInstantiations && method.HasInstantiation && method.GetCanonMethodTarget(CanonicalFormKind.Specific) != method);
-
-            if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) == 0
-                && !IsReflectionBlocked(method))
-            {
-                // Ensure that if SomeMethod<T> is considered reflectable, SomeMethod<ConcreteType> is also reflectable.
-                // We only need this because there's a file format limitation in the reflection mapping tables that
-                // requires generic methods to be concrete (i.e. SomeMethod<__Canon> can never be in the mapping table).
-                // If we ever lift this limitation, this code can be deleted: the reflectability is going to be covered
-                // by GetConditionalDependenciesDueToMethodCodePresence below (we get that callback for SomeMethod<__Canon>).
-                MethodDesc typicalMethod = method.GetTypicalMethodDefinition();
-
-                dependencies ??= new CombinedDependencyList();
-                dependencies.Add(new DependencyNodeCore<NodeFactory>.CombinedDependencyListEntry(
-                    factory.ReflectedMethod(method), factory.ReflectedMethod(typicalMethod), "Reflectability of methods is same across genericness"));
-            }
-        }
-
         public override void GetConditionalDependenciesDueToMethodCodePresence(ref CombinedDependencyList dependencies, NodeFactory factory, MethodDesc method)
         {
             MethodDesc typicalMethod = method.GetTypicalMethodDefinition();
@@ -711,15 +688,6 @@ namespace ILCompiler
             return null;
         }
 
-        public override void GetDependenciesForGenericDictionary(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
-        {
-            // Presence of code might trigger the reflectability dependencies.
-            if ((_generationOptions & UsageBasedMetadataGenerationOptions.CreateReflectableArtifacts) != 0)
-            {
-                GetDependenciesDueToReflectability(ref dependencies, factory, method);
-            }
-        }
-
         public bool GeneratesAttributeMetadata(TypeDesc attributeType)
         {
             var ecmaType = attributeType.GetTypeDefinition() as EcmaType;
index 642dbd8..bfe5ecf 100644 (file)
         <Method Name="Min_Generic_HasExpectedOutput" Dynamic="Required All">
           <GenericArgument Name="System.Int32,System.Runtime" />
         </Method>
+
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Byte,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.SByte,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UInt16,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Int16,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UInt32,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Int32,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UInt64,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Int64,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Single,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Double,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Decimal,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.IntPtr,System.Runtime" />
+        </Method>
+        <Method Name="Min_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UIntPtr,System.Runtime" />
+        </Method>
       </Type>
 
       <Type Name="System.Linq.Tests.MaxTests">
           <GenericArgument Name="System.Int32,System.Runtime" />
         </Method>
 
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Byte,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.SByte,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UInt16,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Int16,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UInt32,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Int32,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UInt64,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Int64,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Single,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Double,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.Decimal,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.IntPtr,System.Runtime" />
+        </Method>
+        <Method Name="Max_AllTypes" Dynamic="Required All">
+          <GenericArgument Name="System.UIntPtr,System.Runtime" />
+        </Method>
       </Type>
 
       <Type Name="System.Linq.Tests.CountTests">