Make preinitialized delegates reflection-visible (#85506)
authorMichal Strehovský <MichalStrehovsky@users.noreply.github.com>
Fri, 28 Apr 2023 13:53:53 +0000 (22:53 +0900)
committerGitHub <noreply@github.com>
Fri, 28 Apr 2023 13:53:53 +0000 (06:53 -0700)
Frozen delegate instances were bypassing the callback to metadata manager that lets metadata manager inject reflection dependencies on delegate construction. Introduce a spot for the callback.

Fixes dotnet/aspnetcore#47941.

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs
src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs
src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs

index 764bffd..0af151d 100644 (file)
@@ -83,6 +83,8 @@ namespace ILCompiler.DependencyAnalysis
                 }
             }
 
+            _data.GetNonRelocationDependencies(ref dependencies, factory);
+
             return dependencies;
         }
 
index 2d8a7d9..989d478 100644 (file)
@@ -11,6 +11,8 @@ using ILCompiler.DependencyAnalysis;
 using Internal.IL;
 using Internal.TypeSystem;
 
+using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
+
 namespace ILCompiler
 {
     // Class that computes the initial state of static fields on a type by interpreting the static constructor.
@@ -1812,6 +1814,7 @@ namespace ILCompiler
         {
             TypeDesc Type { get; }
             void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory);
+            void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory);
             bool IsKnownImmutable { get; }
             int ArrayLength { get; }
         }
@@ -2261,11 +2264,13 @@ namespace ILCompiler
                 data = null;
                 return false;
             }
+
+            public virtual void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory)
+            {
+            }
         }
 
-#pragma warning disable CA1852
-        private class DelegateInstance : AllocatedReferenceTypeValue, ISerializableReference
-#pragma warning restore CA1852
+        private sealed class DelegateInstance : AllocatedReferenceTypeValue, ISerializableReference
         {
             private readonly MethodDesc _methodPointed;
             private readonly ReferenceTypeValue _firstParameter;
@@ -2277,17 +2282,28 @@ namespace ILCompiler
                 _firstParameter = firstParameter;
             }
 
-            public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
-            {
-                Debug.Assert(_methodPointed.Signature.IsStatic == (_firstParameter == null));
-
-                var creationInfo = DelegateCreationInfo.Create(
+            private DelegateCreationInfo GetDelegateCreationInfo(NodeFactory factory)
+                => DelegateCreationInfo.Create(
                     Type.ConvertToCanonForm(CanonicalFormKind.Specific),
                     _methodPointed,
                     constrainedType: null,
                     factory,
                     followVirtualDispatch: false);
 
+            public override void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory)
+            {
+                DelegateCreationInfo creationInfo = GetDelegateCreationInfo(factory);
+
+                MethodDesc targetMethod = creationInfo.PossiblyUnresolvedTargetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
+                factory.MetadataManager.GetDependenciesDueToDelegateCreation(ref dependencies, factory, targetMethod);
+            }
+
+            public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
+            {
+                Debug.Assert(_methodPointed.Signature.IsStatic == (_firstParameter == null));
+
+                DelegateCreationInfo creationInfo = GetDelegateCreationInfo(factory);
+
                 Debug.Assert(!creationInfo.TargetNeedsVTableLookup);
 
                 // MethodTable
@@ -2340,9 +2356,7 @@ namespace ILCompiler
             public int ArrayLength => throw new NotSupportedException();
         }
 
-#pragma warning disable CA1852
-        private class ArrayInstance : AllocatedReferenceTypeValue, ISerializableReference
-#pragma warning restore CA1852
+        private sealed class ArrayInstance : AllocatedReferenceTypeValue, ISerializableReference
         {
             private readonly int _elementCount;
             private readonly int _elementSize;
@@ -2405,7 +2419,7 @@ namespace ILCompiler
                 builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this));
             }
 
-            public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
+            public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
             {
                 // MethodTable
                 var node = factory.ConstructedTypeSymbol(Type);
@@ -2518,9 +2532,7 @@ namespace ILCompiler
             ByRefValue IHasInstanceFields.GetFieldAddress(FieldDesc field) => new FieldAccessor(_value).GetFieldAddress(field);
         }
 
-#pragma warning disable CA1852
-        private class ObjectInstance : AllocatedReferenceTypeValue, IHasInstanceFields, ISerializableReference
-#pragma warning restore CA1852
+        private sealed class ObjectInstance : AllocatedReferenceTypeValue, IHasInstanceFields, ISerializableReference
         {
             private readonly byte[] _data;
 
@@ -2574,7 +2586,7 @@ namespace ILCompiler
                 builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this));
             }
 
-            public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
+            public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
             {
                 // MethodTable
                 var node = factory.ConstructedTypeSymbol(Type);
index 6f16508..ed28083 100644 (file)
@@ -36,6 +36,7 @@ internal class Program
         TestBadClass.Run();
         TestRefs.Run();
         TestDelegate.Run();
+        TestDelegateReflectionVisible.Run();
         TestInitFromOtherClass.Run();
         TestInitFromOtherClassDouble.Run();
         TestDelegateToOtherClass.Run();
@@ -610,6 +611,19 @@ class TestDelegate
     }
 }
 
+class TestDelegateReflectionVisible
+{
+    static readonly Action s_a = DelegateTarget;
+
+    static void DelegateTarget() { }
+
+    public static void Run()
+    {
+        Assert.IsPreinitialized(typeof(TestDelegateReflectionVisible));
+        Assert.AreEqual(nameof(DelegateTarget), s_a.Method.Name);
+    }
+}
+
 class TestInitFromOtherClass
 {
     class OtherClass