-
Notifications
You must be signed in to change notification settings - Fork 5.1k
Optimize DispatchProxy generated code #47134
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
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 need to make sure reflection-accessing reflection surface area results in a trimming warning. Invoking reflection APIs with parameters that illink didn't see is not safe.
Cc @vitek-karas I filed dotnet/linker#1764.
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.
Good call.
In this case, the usage is "safe" since the type arguments all come from the user's code. So any requirements on the types will be seen by the linker there.
Here was the original suppression:
runtime/src/libraries/System.Reflection.DispatchProxy/src/System/Reflection/DispatchProxyGenerator.cs
Lines 149 to 157 in 9f1c913
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.
Sigh, maybe DispatchProxy is not trimming safe after all.
If we make a DispatchProxy for this, who is going to enforce that the
Type
returned from the implementation ofGetTheType
matches the requirements?There was a discussion whether we need to mark the interface methods as reflected up here: #46715 (comment)
I think we have to. And if we do that and once dotnet/linker#1764 is fixed, this will generate a warning because we in fact cannot statically enforce that this will hold.
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.
I meant to say "not trimming safe for all possible interfaces". This would only warn if the interface has the DynamicallyAccessed annotations.
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 will probably have to take this into account - see dotnet/linker#1607 (comment). Originally I though that return value annotations are not affected, since they apply to the implementation not the caller, but with TypeBuilder I can provide implementation to annotated method without linker seeing it that way.
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.
@MichalStrehovsky that would mean that we need to mark the interface type in the proxy with
All
as well - so that linker would "mark as reflection" all of the interfaces and all the members on them. With the fix in dotnet/linker#1764 that would lead to generating a warning in the above case.If we don't mark it as
All
, we would not be able to catch this. Ideally we would need some annotation like "consider all used methods on this type/interface as accessed via reflection" - but that's way too specific annotation to create. SoAll
is probably the best for now.So to answer @eerhardt question:
All
- I know we originally reverted that, but given the above, I don't see a better way currently. It's probably not a big size concern anyway, since it will only increase the size of the proxy itself, which is typically very small (each method's implementation is pretty trivial).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.
This is the part I don't understand. If a method on an interface is marked as
DynamicallyAccessed
and isn't being used, why would we need to warn about it? In the scenario above,GetTheType()
is called. So I guess I don't understand how annotating the interface asAll
should change anything here.Uh oh!
There was an error while loading. Please reload this page.
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.
Annotating it as
All
will trigger a warning at the callsite to DispatchProxy'sCreate
once dotnet/linker#1764 is addressed and the interface has any methods that have annotations. The purpose is just to trigger the warning when creating a DispatchProxy for an annotated interface. It's not about preserving stuff.If it's not annotated and we're suppressing the warning within the method body there's no place that would warn in such situation.
Linker needs to see that the interface method is potentially reflection-accessed.
Basically, the problem is that there's a suppression on the call to
TypeBuilder.AddInterfaceImplementation
within theDispatchProxy
code. This will never be safe to suppress if the interface is user-provided.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 a lot @MichalStrehovsky for the explanation. Another way to look at it is: Each annotation has two sides to it. The code which assigns value to "it" and the code which uses the value from "it". Linker needs to validate both sides. In the case of an annotation on a return value, the code which assigns the value is the method's body, and the code which uses the value is the caller. In this case with dispatch proxy and the interface method, the caller is known (as you mention there will be call to this method somewhere in the app's code), but the method's body is not known to linker - it will be created at runtime via
TypeBuilder
. So linker can only validate one side - which is not enough.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.
Here's a sample I used to wrap my head around this:
Linker will not keep the ctor of
Unused
but there's also no warning. So I was thinking "what's the spot that should have warned". The spot was theTypeBuilder.AddInterfaceImplementation
that we suppressed - linker needs to see that we reflection-access the interface methods. Propagating that annotation out to the public API surface will make sure there is a warning for this case (once the above mentioned bug is fixed), because indeed illink cannot prove that this will work.Suppressions need a lot of scrutiny :(.