Skip to content

Add DynamicallyAccessedMemberTypes.AllMethods/.AllFields/.AllEvents/etc #88512

Closed
@MichalStrehovsky

Description

@MichalStrehovsky

We currently use DynamicallyAccessedMemberTypes.All in a couple places within libraries. Most uses that I know of fall back to this because they need to access non-public members recursively from their bases and .All is the only DAMT that allows this.

The existing DAMT annotations are modeled after reflection APIs/BindingFlags and that doesn't gel well with code that iterates base types and looks at private stuff in the bases.

We defined .All to be quite broad (it e.g. includes all methods on any interface the targeted type implements). It can hurt size badly.

I'm looking at the Stage2 app where dataflow came up with a ton of reflection roots. I did a quick hack to make .All at least not root everything on implemented interfaces (we're unlikely to rely on this anywhere) and I'm seeing 6.7% savings from that alone. It is probably too late to scale back what .All means (even though I'd really be surprised if anyone relies on the fact that .All on a class keeps all methods on interfaces), but if we can migrate code from using .All to do something more targeted, we'll get the 6.7% size savings and likely even more.

Click to expand the diff for the hack I did

Baseline:
Compare:

diff --git a/src/coreclr/tools/Common/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs b/src/coreclr/tools/Common/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs
index 6780cb56192..b139a4421d2 100644
--- a/src/coreclr/tools/Common/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs
+++ b/src/coreclr/tools/Common/Compiler/Dataflow/DynamicallyAccessedMembersBinder.cs
@@ -469,7 +469,7 @@ private static void GetAllOnType(TypeDesc type, bool declaredOnly, List<TypeSyst
                 foreach (DefType interfaceType in type.TryGetExplicitlyImplementedInterfaces())
                 {
                     members.Add(interfaceType);
-                    GetAllOnType(interfaceType, declaredOnly: false, members, types);
+                    //GetAllOnType(interfaceType, declaredOnly: false, members, types);
                 }
             }
 
diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
index 79c0cf011bf..43d089dddac 100644
--- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
+++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMethodBodyScanner.cs
@@ -155,7 +155,7 @@ public static DependencyList ProcessTypeGetTypeDataflow(NodeFactory factory, Flo
             // annotations to interfaces separately if dealing with DAMT.All or DAMT.Interfaces.
             if (annotation.HasFlag(DynamicallyAccessedMemberTypes.Interfaces))
             {
-                var annotationToApplyToInterfaces = annotation == DynamicallyAccessedMemberTypes.All ? annotation : DynamicallyAccessedMemberTypes.Interfaces;
+                var annotationToApplyToInterfaces = /*annotation == DynamicallyAccessedMemberTypes.All ? annotation :*/ DynamicallyAccessedMemberTypes.Interfaces;
                 foreach (var iface in type.RuntimeInterfaces)
                 {
                     if (flowAnnotations.GetTypeAnnotation(iface).HasFlag(annotationToApplyToInterfaces))

API Proposal

namespace System.Diagnostics.CodeAnalysis;

public enum DynamicallyAccessedMemberTypes
{
    // Existing members
    // ...

    // New members:
    AllConstructors = 0x4000 | PublicConstructors | NonPublicConstructors,
    AllMethods = 0x8000 | PublicMethods | NonPublicMethods,
    AllFields = 0x10000 | PublicFields | NonPublicFields,
    AllNestedTypes = 0x20000 | PublicNestedTypes | NonPublicNestedTypes,
    AllProperties = 0x40000 | PublicProperties | NonPublicProperties,
    AllEvents = 0x80000 | PublicEvents | NonPublicEvents,
}

The proposed All* members would do the obvious thing: they will keep all members of the specified kind on the type and its bases. They will not go to interfaces.

Cc @dotnet/illink @eerhardt

Metadata

Metadata

Assignees

No one assigned

    Labels

    api-approvedAPI was approved in API review, it can be implementedarea-Tools-ILLink.NET linker development as well as trimming analyzersin-prThere is an active PR which will close this issue when it is mergedlinkable-frameworkIssues associated with delivering a linker friendly framework

    Type

    No type

    Projects

    Status

    No status

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions