Skip to content

Commit e6f9af1

Browse files
Make preinitialized delegates reflection-visible (#85506)
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.
1 parent 42e397b commit e6f9af1

File tree

3 files changed

+44
-16
lines changed

3 files changed

+44
-16
lines changed

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/DependencyAnalysis/FrozenObjectNode.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto
8383
}
8484
}
8585

86+
_data.GetNonRelocationDependencies(ref dependencies, factory);
87+
8688
return dependencies;
8789
}
8890

src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/TypePreinit.cs

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
using Internal.IL;
1212
using Internal.TypeSystem;
1313

14+
using DependencyList = ILCompiler.DependencyAnalysisFramework.DependencyNodeCore<ILCompiler.DependencyAnalysis.NodeFactory>.DependencyList;
15+
1416
namespace ILCompiler
1517
{
1618
// Class that computes the initial state of static fields on a type by interpreting the static constructor.
@@ -1812,6 +1814,7 @@ public interface ISerializableReference : ISerializableValue
18121814
{
18131815
TypeDesc Type { get; }
18141816
void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory);
1817+
void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory);
18151818
bool IsKnownImmutable { get; }
18161819
int ArrayLength { get; }
18171820
}
@@ -2261,11 +2264,13 @@ public override bool GetRawData(NodeFactory factory, out object data)
22612264
data = null;
22622265
return false;
22632266
}
2267+
2268+
public virtual void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory)
2269+
{
2270+
}
22642271
}
22652272

2266-
#pragma warning disable CA1852
2267-
private class DelegateInstance : AllocatedReferenceTypeValue, ISerializableReference
2268-
#pragma warning restore CA1852
2273+
private sealed class DelegateInstance : AllocatedReferenceTypeValue, ISerializableReference
22692274
{
22702275
private readonly MethodDesc _methodPointed;
22712276
private readonly ReferenceTypeValue _firstParameter;
@@ -2277,17 +2282,28 @@ public DelegateInstance(TypeDesc delegateType, MethodDesc methodPointed, Referen
22772282
_firstParameter = firstParameter;
22782283
}
22792284

2280-
public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
2281-
{
2282-
Debug.Assert(_methodPointed.Signature.IsStatic == (_firstParameter == null));
2283-
2284-
var creationInfo = DelegateCreationInfo.Create(
2285+
private DelegateCreationInfo GetDelegateCreationInfo(NodeFactory factory)
2286+
=> DelegateCreationInfo.Create(
22852287
Type.ConvertToCanonForm(CanonicalFormKind.Specific),
22862288
_methodPointed,
22872289
constrainedType: null,
22882290
factory,
22892291
followVirtualDispatch: false);
22902292

2293+
public override void GetNonRelocationDependencies(ref DependencyList dependencies, NodeFactory factory)
2294+
{
2295+
DelegateCreationInfo creationInfo = GetDelegateCreationInfo(factory);
2296+
2297+
MethodDesc targetMethod = creationInfo.PossiblyUnresolvedTargetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific);
2298+
factory.MetadataManager.GetDependenciesDueToDelegateCreation(ref dependencies, factory, targetMethod);
2299+
}
2300+
2301+
public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
2302+
{
2303+
Debug.Assert(_methodPointed.Signature.IsStatic == (_firstParameter == null));
2304+
2305+
DelegateCreationInfo creationInfo = GetDelegateCreationInfo(factory);
2306+
22912307
Debug.Assert(!creationInfo.TargetNeedsVTableLookup);
22922308

22932309
// MethodTable
@@ -2340,9 +2356,7 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
23402356
public int ArrayLength => throw new NotSupportedException();
23412357
}
23422358

2343-
#pragma warning disable CA1852
2344-
private class ArrayInstance : AllocatedReferenceTypeValue, ISerializableReference
2345-
#pragma warning restore CA1852
2359+
private sealed class ArrayInstance : AllocatedReferenceTypeValue, ISerializableReference
23462360
{
23472361
private readonly int _elementCount;
23482362
private readonly int _elementSize;
@@ -2405,7 +2419,7 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
24052419
builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this));
24062420
}
24072421

2408-
public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
2422+
public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
24092423
{
24102424
// MethodTable
24112425
var node = factory.ConstructedTypeSymbol(Type);
@@ -2518,9 +2532,7 @@ public override bool GetRawData(NodeFactory factory, out object data)
25182532
ByRefValue IHasInstanceFields.GetFieldAddress(FieldDesc field) => new FieldAccessor(_value).GetFieldAddress(field);
25192533
}
25202534

2521-
#pragma warning disable CA1852
2522-
private class ObjectInstance : AllocatedReferenceTypeValue, IHasInstanceFields, ISerializableReference
2523-
#pragma warning restore CA1852
2535+
private sealed class ObjectInstance : AllocatedReferenceTypeValue, IHasInstanceFields, ISerializableReference
25242536
{
25252537
private readonly byte[] _data;
25262538

@@ -2574,7 +2586,7 @@ public override void WriteFieldData(ref ObjectDataBuilder builder, NodeFactory f
25742586
builder.EmitPointerReloc(factory.SerializedFrozenObject(AllocationSite.OwningType, AllocationSite.InstructionCounter, this));
25752587
}
25762588

2577-
public virtual void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
2589+
public void WriteContent(ref ObjectDataBuilder builder, ISymbolNode thisNode, NodeFactory factory)
25782590
{
25792591
// MethodTable
25802592
var node = factory.ConstructedTypeSymbol(Type);

src/tests/nativeaot/SmokeTests/Preinitialization/Preinitialization.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ private static int Main()
3636
TestBadClass.Run();
3737
TestRefs.Run();
3838
TestDelegate.Run();
39+
TestDelegateReflectionVisible.Run();
3940
TestInitFromOtherClass.Run();
4041
TestInitFromOtherClassDouble.Run();
4142
TestDelegateToOtherClass.Run();
@@ -610,6 +611,19 @@ public static void Run()
610611
}
611612
}
612613

614+
class TestDelegateReflectionVisible
615+
{
616+
static readonly Action s_a = DelegateTarget;
617+
618+
static void DelegateTarget() { }
619+
620+
public static void Run()
621+
{
622+
Assert.IsPreinitialized(typeof(TestDelegateReflectionVisible));
623+
Assert.AreEqual(nameof(DelegateTarget), s_a.Method.Name);
624+
}
625+
}
626+
613627
class TestInitFromOtherClass
614628
{
615629
class OtherClass

0 commit comments

Comments
 (0)