-
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
Analyzer Proposal: Recommend use of concrete types to maximize devirtualization potential #51193
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
I already implemented the rule in my analyzer https://github.com/NetFabric/NetFabric.Hyperlinq.Analyzer/blob/master/docs/reference/HLQ001_AssignmentBoxing.md |
Yeah, that's the general idea. Although your analysis is specialized for enumerables, I'm proposing something more general. Basically, if a field, variable or private method parameter is only ever assigned a concrete type, then that element should be declared of that type rather than be declared using an interface type or a base type. PS: I like your analyzer, I'm going to look at using it in our projects :-) |
CC @AndyAyersMS @dotnet/jit-contrib |
This doesn't seem like a codegen issue, though having stronger type info definitely will help the jit generate better code. @stephentoub perhaps you can suggest a more appropriate area label? |
Technically such a change can introduce behavioral changes, if the public API on the concrete substituted type differs in behavior from the interface it's replacing, e.g. if the field was But, such an impact should be relatively rare, and it probably just impacts what level we choose to default the rule to, e.g. hidden. There are other non-devirtualization benefits to this as well, e.g. if you have: private IList<int> _list = ...; and then code that enumerates it: foreach (int i in _list) { ... } that enumeration will be much more efficient if the field is: private List<int> _list = ...; avoiding enumerator allocation, interface dispatch in the enumeration, etc. |
As far as performance is concerned, the best results happen when this goes from an interface to a sealed type, but there's still goodness in moving up to a more-derived type (and less so for a more-derived interface). The main identified complication is when a field, auto-property or variable is declared of an interface and changing it to a concrete type causes a compile failure (or runtime behavior) because of explicit interface implementations.
Do not run on public or protected fields (or auto-properties) -- or This may, in the case of explicit interface implementations, cause code to change or fail to compile, but we think we're OK with that.
|
@dotnet/jit-contrib I marked this as up for grabs, if no one is currently working on this. @aalmada you mentioned you already had an implementation of this analyzer. Would you like to work on this? (f the members of @dotnet/jit-contrib are ok with that). |
@geeknoid, do you want to open a PR to dotnet/roslyn-analyzers for this? |
Yep, on my todo list :-) |
Great |
* Add the UseConreteType analyzer As per dotnet/runtime#51193. This recommends using concrete types for fields, local, parameters, and method returns instead of interface/abstract types when possible and when it doesn't affect the API surface of a class. The idea is to help eliminate virtual/interface dispatch, while also making available potentially richer APIs exposed by implementations relative to their interface. * Updates Co-authored-by: Martin Taillefer <[email protected]>
* Add the UseConreteType analyzer As per dotnet/runtime#51193. This recommends using concrete types for fields, local, parameters, and method returns instead of interface/abstract types when possible and when it doesn't affect the API surface of a class. The idea is to help eliminate virtual/interface dispatch, while also making available potentially richer APIs exposed by implementations relative to their interface. * Updates Co-authored-by: Martin Taillefer <[email protected]> Original commit: dotnet/roslyn-analyzers@2f82379 [[ commit created by automation ]]
Implemented in dotnet/roslyn-analyzers#6370 |
Enabling the JIT to devirtualize has a number of benefits as outlined in #49944. To aid in that process, it is preferable to use concrete types rather than interfaces. In particular, private fields, local variables, and private and/or internal method parameters all benefit from being concrete types.
So for example:
is preferable (perf-wise) to:
By reporting warnings only on private fields, variables, private+internal method parameters, the analyzer would not induce any change in the API surface of a component, where interfaces are often desirable. But it can help speed up the inner-workings of components by fostering devirtualization and hence inlining.
The text was updated successfully, but these errors were encountered: