-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
Make TypeComponentsCache trimmable #80726
Conversation
Contributes to dotnet#80165. The compiler is not able to get rid of the call to `PerNameQueryCache<M>.Factory` virtual method due to generic code sharing. Making this not shareable allows trimming it because now we can see `ConcurrentUnifier<StringKey, __Canon>.Factory` is never called (whereas `ConcurrentUnifier<__Canon, __Canon>.Factory` is called). This is a ~5 kB regression for apps that do use reflection. We could explore different strategies to make this trimmable and not be a size regression, but I'm not sure if it's really worth it. We'd like to get rid of this reflection stack implementation anyway and replace it with something more lightweight.
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsContributes to #80165. The compiler is not able to get rid of the call to This is a ~5 kB regression for apps that do use reflection. We could explore different strategies to make this trimmable and not be a size regression, but I'm not sure if it's really worth it. We'd like to get rid of this reflection stack implementation anyway and replace it with something more lightweight. Cc @dotnet/ilc-contrib
|
// actually used in an app that is light on reflection use. But we do have other canonically equivalent | ||
// ConcurrentUnifier instances in the program and their use could drag this implementation into the app. | ||
// Making the ConcurrentUnifier instance unshareable gives the compiler the ability to unshare this. | ||
private struct StringKey : IEquatable<StringKey> |
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 this be a readonly record struct
? Or is it not allowed in System.Private.CoreLib?
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.
We don't use records in CoreLib (or probably all of runtime repo in general). They add a lot more overhead than they're worth. Trading a couple lines of code for kilobytes of footprint for everyone who uses this is not a good tradeoff.
Recently: dotnet/aspnetcore#45604 (comment)
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.
My assumption was that this could be trimmed but I guess not. Time to read docs on trimming in more detail, thanks for the explanation.
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.
The problem is that a lot of the conveniences records bring is behind interfaces and virtual methods. E.g. ToString
. It's hard to get rid of ToString
.
I'm marking this as no-review. As I was working on another piece of #80165 I came to realization that we'll probably need the components cache for nested types, but not the others, so this might require a different shape of the fix. |
I've changed the way to do this and updated top-post with the description. This is ready for review. |
Follow up to dotnet#80726. Needed a bit more laziness to really get everything out of the picture.
Follow up to #80726. Needed a bit more laziness to really get everything out of the picture.
Contributes to dotnet#80165. Dispensing of reflection member infos is done through a member policies class. This is a generic class that has specialized implementations for each kind of member info. It used a clever trick to get to the specific implementations. Just access `MemberPolicies<EventInfo>.Default` to get one for events or `MemberPolicies<PropertyInfo>.Default` to get one for properties. It was also absolutely not trimming friendly. This change removes the clever trick and replaces it with good old fashioned parameter passing.
Follow up to dotnet#80726. Needed a bit more laziness to really get everything out of the picture.
Contributes to #80165.
Dispensing of reflection member infos is done through a member policies class. This is a generic class that has specialized implementations for each kind of member info.
It used a clever trick to get to the specific implementations. Just access
MemberPolicies<EventInfo>.Default
to get one for events orMemberPolicies<PropertyInfo>.Default
to get one for properties. It was also absolutely not trimming friendly.This change removes the clever trick and replaces it with good old fashioned parameter passing.
Cc @dotnet/ilc-contrib