-
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
Precise reflection-visible delegate target analysis #96166
Precise reflection-visible delegate target analysis #96166
Conversation
Before this change, the compiler considered all methods that are target of a delegate reflection-visible. This is because one can just call `Delegate.Method` on a delegate instance to obtain a `MethodBase` of the target. This is rather annoying because most delegates are not actually used with reflection. In this PR I'm adding analysis of places that use `Delegate.Method` to reflect on certain delegate type. This builds on top of the existing dataflow analysis within the compiler - we can often see the exact delegate type that was reflected on. When we see that, we make all targets of that specific type reflection-visible. The advantage is that if nobody ever calls `Delegate.Method`, no delegates are made reflection visible. If this is used with a certain known delegate type, only the methods pointed to by that specific delegate type are made reflection visible. And if this is used with something typed at `Delegate` or `MulticastDelegate`, we fall back to the old behavior that just makes everything reflection visible. I was hoping this would help ASP.NET but ASP.NET actually uses something typed as `Delegate` to obtain the `MethodInfo` and there's more code somewhere in the `Task` infrastructure (under `EventSourceSupport`) that also does it. So it unfortunately can't help there.
Tagging subscribers to this area: @agocke, @MichalStrehovsky, @jkotas Issue DetailsBefore this change, the compiler considered all methods that are target of a delegate reflection-visible. This is because one can just call In this PR I'm adding analysis of places that use The advantage is that if nobody ever calls I was hoping this would help ASP.NET but ASP.NET actually uses something typed as Cc @dotnet/ilc-contrib
|
Any numbers to demonstrate where it helps?
Are these cases fixable? |
Don't have numbers right now but it's for things like this in CsWinRT: Notice tons of delegates being created under various checks that RyuJIT can optimize. But whole program analysis figures out all of these generic flavors are targets of reflection before the optimizations starts kicking in (because IL scanner doesn't do these optimizations and we create delegates, therefore the target is force-reflection-visible in the whole program view).
I didn't look at it because this one doesn't look fixable and ASP.NET without EventSourceSupport seems like an academic scenario: runtime/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs Line 1687 in 396edb2
|
Had to move this out because it depends on async stuff and that one makes it impossible to optimize out `Delegate.Method` with a debug corelib.
This one is fixable by introducing a new diagnostic-only API for delegates that uses stacktrace data, that comes with similar disclaimer as stacktrace APIs. Where is the one in ASP.NET? |
Is this precision useful in practice? Or would be good enough to just check for |
This is the full list in BasicMinimalApi:
The complete list of callsites in BasicMinimalApi is this, but we know the type of the delegate in most places: From this I get that people want to use this API and if we can make using it less costly, it's nice. Apps have many delegates. Most are not reflected on. If I were to drop the per-type part from the PR, it wouldn't get much shorter. Most of the analysis we're already getting for free from dataflow. |
Hmm, this one does more than just producing a pretty name - it inspects custom attributes, etc. It may be fixable with source generator, but it does not look easy. |
LGTM. Thank you! We should open two follow workitems:
If both of these follow up items are implemented, this optimization should be able kick in for ASP.NET apps too. |
Filed #96528. I folded it together with a |
Filed dotnet/aspnetcore#53171 |
I was now able to measure impact in CsWinRT and seeing around 5%. I don't expect ASP.NET to get this much because CsWinRT was all kinds of a pathogenic case, but maybe some. |
Before this change, the compiler considered all methods that are target of a delegate reflection-visible. This is because one can just call
Delegate.Method
on a delegate instance to obtain aMethodBase
of the target. This is rather annoying because most delegates are not actually used with reflection.In this PR I'm adding analysis of places that use
Delegate.Method
to reflect on certain delegate type. This builds on top of the existing dataflow analysis within the compiler - we can often see the exact delegate type that was reflected on. When we see that, we make all targets of that specific type reflection-visible.The advantage is that if nobody ever calls
Delegate.Method
, no delegates are made reflection visible. If this is used with a certain known delegate type, only the methods pointed to by that specific delegate type are made reflection visible. And if this is used with something typed asDelegate
orMulticastDelegate
, we fall back to the old behavior that just makes everything reflection visible.I was hoping this would help ASP.NET but ASP.NET actually uses something typed as
Delegate
to obtain theMethodInfo
and there's more code somewhere in theTask
infrastructure (underEventSourceSupport
) that also does it. So it unfortunately can't help there.Cc @dotnet/ilc-contrib