Skip to content
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

Add missing readonly modifiers to GCHandle and DependentHandle #93178

Merged

Conversation

Sergio0694
Copy link
Contributor

This PR sprinkles a bunch of missing readonly modifiers to APIs of GCHandle and DependentHandle that are not actually modifying instance state. This allows Roslyn to skip some unnecessary defensive copies when invoking any of these APIs over values stored in either readonly fields, or from members marked as readonly (from mutable struct types).

@ghost ghost added the community-contribution Indicates that the PR has been added by a community member label Oct 7, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label Oct 7, 2023
@Sergio0694 Sergio0694 force-pushed the user/sergiopedri/add-more-readonly branch from 0e536d1 to be84974 Compare October 7, 2023 19:15
@jkotas
Copy link
Member

jkotas commented Oct 8, 2023

values stored in either readonly fields

Storing GCHandles in readonly fields is a pit of failure. Consider:

using System.Runtime.InteropServices;

var t = new Test();
t.Dispose();

class Test
{
    readonly GCHandle _handle = GCHandle.Alloc(null);

    public void Dispose()
    {
         Console.WriteLine(_handle.IsAllocated);

         _handle.Free();

         // This prints `true` even though the handle was just freed!
         Console.WriteLine(_handle.IsAllocated);
    }
}

This change does not hurt, but I would avoid storing the GCHandles in readonly fields in the first place.

@jkotas jkotas added area-System.Runtime.InteropServices and removed needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners labels Oct 8, 2023
@ghost
Copy link

ghost commented Oct 8, 2023

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

Issue Details

This PR sprinkles a bunch of missing readonly modifiers to APIs of GCHandle and DependentHandle that are not actually modifying instance state. This allows Roslyn to skip some unnecessary defensive copies when invoking any of these APIs over values stored in either readonly fields, or from members marked as readonly (from mutable struct types).

Author: Sergio0694
Assignees: -
Labels:

area-System.Runtime.InteropServices, community-contribution, needs-area-label

Milestone: -

@Sergio0694
Copy link
Contributor Author

@jkotas I agree that's not a good idea, the real scenario I was thinking about (and the reason why I made this PR) was more about allowing instance methods touching GC handles stored on mutable fields to be marked as readonly without causing defensive copies (eg. if they're just accessing the target of the handle). As a side note I still wish there was some way (or an analyzer perhaps) to spot defensive copies. It's so easy to accidentally invoke a non readonly member on a value that triggers a defensive copy for one reason or another 🥲

@stephentoub
Copy link
Member

Can you highlight any places where a) this avoids defensive copies, b) those copies involve additional cost, and c) that cost is measurable in any meaningful way?

@Sergio0694 Sergio0694 force-pushed the user/sergiopedri/add-more-readonly branch from bdefd85 to 81d7454 Compare October 16, 2023 14:20
@Sergio0694
Copy link
Contributor Author

Replying here, I'm responding to a bunch of comments from several threads above as well as emails.

Chatted with @AaronRobinsonMSFT offline, and I've updated this PR to only add readonly to getters, not setters.

"Can you highlight any places where a) this avoids defensive copies, b) those copies involve additional cost, and c) that cost is measurable in any meaningful way?"

I can't, no. This is more of a "conceptual" change (ie. adding readonly here just seems correct on its own, and I'm not proposing the change specifically to fix some performance issue I noticed). At least in simple tests, the JIT seems to produce equivalent codegen. However, the IL is certainly more bloated without readonly (ie. it has one extra local and whatnot), so this still just seems to "make things simpler" for the JIT, like @tannergooding also mentioned.

@stephentoub
Copy link
Member

stephentoub commented Oct 16, 2023

"Can you highlight any places where a) this avoids defensive copies, b) those copies involve additional cost, and c) that cost is measurable in any meaningful way?"

I can't, no. This is more of a "conceptual" change (ie. adding readonly here just seems correct on its own, and I'm not proposing the change specifically to fix some performance issue I noticed). At least in simple tests, the JIT seems to produce equivalent codegen. However, the IL is certainly more bloated without readonly (ie. it has one extra local and whatnot), so this still just seems to "make things simpler" for the JIT, like @tannergooding also mentioned.

Thanks. It's not worth making the public API more confusing (making a setter readonly) to make the JIT's life a little bit easier, especially when it's already doing just fine here.

@AaronRobinsonMSFT
Copy link
Member

@jkotas and @stephentoub After the most recent updates, I don't see any obvious concerns with these changes. Do either of you concerns with going forward with these changes? An alternative would be to focus on #94134 as opposed to making changes to GCHandle.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks fine to me.

@AaronRobinsonMSFT AaronRobinsonMSFT merged commit f1d463f into dotnet:main Nov 14, 2023
172 of 174 checks passed
@Sergio0694 Sergio0694 deleted the user/sergiopedri/add-more-readonly branch November 30, 2023 15:35
@github-actions github-actions bot locked and limited conversation to collaborators Dec 31, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Runtime.InteropServices community-contribution Indicates that the PR has been added by a community member
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants