-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Emit less metadata for not-reflection-visible types #91660
Conversation
In .NET 8 we massively regressed the size of an empty WinForms app. A WinForms app now brings in a big chunk of WPF with it. I traced it down to the `ICommand` interface having a WPF `TypeConverter` and `ValueSerializer` attribute on it: https://github.com/dotnet/runtime/blob/04bd438844482c907062583153a43a9e3b37dbb8/src/libraries/System.ObjectModel/src/System/Windows/Input/ICommand.cs#L13-L16. An empty app will have a call to a method on `ICommand`, but nothing actually implements `ICommand`. Previously this would mean we generate an unconstructed `MethodTable` for `ICommand`, the unconstructed `MethodTable`s get no reflection metadata, and that's the end of the story. After dotnet#85810 however, the reflection stack can no longer reason about `MethodTable`s that don't have reflection metadata, so we need to generate it. This means we end up with the custom attribute and all the reflection dataflow that comes out of it. But this metadata is not actually visible in trim safe apps (the only place where reflection could see these method tables in trim safe code is if they're used in a type comparison `x == typeof(Foo)` and we were able to optimize the method table to the unconstructed version because of that). So we can generate less of it and still get away with it. In this PR I'm adding support for skipping generation of custom attribute metadata for such types. The size of an empty WinForms app goes from 50-something MB to 20-something MB. I think we'll be able to further reduce this number to ~7 MB or less because 12 MB of this are embedded resources that look designer related.
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsIn .NET 8 we massively regressed the size of an empty WinForms app. A WinForms app now brings in a big chunk of WPF with it. I traced it down to the runtime/src/libraries/System.ObjectModel/src/System/Windows/Input/ICommand.cs Lines 13 to 16 in 04bd438
An empty app will have a call to a method on After #85810 however, the reflection stack can no longer reason about But this metadata is not actually visible in trim safe apps (the only place where reflection could see these method tables in trim safe code is if they're used in a type comparison In this PR I'm adding support for skipping generation of custom attribute metadata for such types. The size of an empty WinForms app goes from 50-something MB to 20-something MB. I think we'll be able to further reduce this number to ~7 MB or less because 12 MB of this are embedded resources that look designer related. Cc @dotnet/ilc-contrib
|
@@ -24,11 +24,13 @@ namespace ILCompiler.DependencyAnalysis | |||
internal sealed class TypeMetadataNode : DependencyNodeCore<NodeFactory> | |||
{ | |||
private readonly MetadataType _type; | |||
private readonly bool _isMinimal; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please add a comment describing what it means for type metadata to be "minimal"?
And why is it OK to not include custom attributes in this case for example.
@@ -100,7 +110,7 @@ public override IEnumerable<DependencyListEntry> GetStaticDependencies(NodeFacto | |||
/// Decomposes a constructed type into individual <see cref="TypeMetadataNode"/> units that will be needed to | |||
/// express the constructed type in metadata. | |||
/// </summary> | |||
public static void GetMetadataDependencies(ref DependencyList dependencies, NodeFactory nodeFactory, TypeDesc type, string reason) | |||
public static void GetMetadataDependencies(ref DependencyList dependencies, NodeFactory nodeFactory, TypeDesc type, string reason, bool isFullType = true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Personally, I find it confusing the "minimal"/"full" usage. If they're complementary (type is either minimal or full, but nothing else), then I would prefer to use only one of the two terms and negation.
If they're not complementary then I think there should be a comment somewhere describing the differences and where/how it's used.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tried to address both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
/azp run runtime-extra-platforms |
Azure Pipelines successfully started running 1 pipeline(s). |
/backport to release/8.0 |
Started backporting to release/8.0: https://github.com/dotnet/runtime/actions/runs/6103552055 |
This reverts commit 0bfc0c9.
…ypes (#91660)" (#91989) * Revert "Emit less metadata for not-reflection-visible types (#91660)" This reverts commit 0bfc0c9. * Regression test --------- Co-authored-by: Michal Strehovský <MichalStrehovsky@users.noreply.github.com> Co-authored-by: Carlos Sánchez López <1175054+carlossanlop@users.noreply.github.com>
In .NET 8 we massively regressed the size of an empty WinForms app. A WinForms app now brings in a big chunk of WPF with it. I traced it down to the
ICommand
interface having a WPFTypeConverter
andValueSerializer
attribute on it:runtime/src/libraries/System.ObjectModel/src/System/Windows/Input/ICommand.cs
Lines 13 to 16 in 04bd438
An empty app will have a call to a method on
ICommand
, but nothing actually implementsICommand
. Previously this would mean we generate an unconstructedMethodTable
forICommand
, the unconstructedMethodTable
s get no reflection metadata, and that's the end of the story.After #85810 however, the reflection stack can no longer reason about
MethodTable
s that don't have reflection metadata, so we need to generate it. This means we end up with the custom attribute and all the reflection dataflow that comes out of it.But this metadata is not actually visible in trim safe apps (the only place where reflection could see these method tables in trim safe code is if they're used in a type comparison
x == typeof(Foo)
and we were able to optimize the method table to the unconstructed version because of that). So we can generate less of it and still get away with it.In this PR I'm adding support for skipping generation of custom attribute metadata for such types. The size of an empty WinForms app goes from 50-something MB to 20-something MB. I think we'll be able to further reduce this number to ~7 MB or less because 12 MB of this are embedded resources that look designer related.
Cc @dotnet/ilc-contrib