Description
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
Labels
Type
Projects
Status