-
Notifications
You must be signed in to change notification settings - Fork 5.2k
Add GCHandle<T> #111307
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 GCHandle<T> #111307
Conversation
|
Note regarding the |
1 similar comment
|
Note regarding the |
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandleExtensions.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs
Outdated
Show resolved
Hide resolved
Sergio0694
left a 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.
Left a few notes based on previous discussions 🙂
Thank you for taking this one!
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs
Outdated
Show resolved
Hide resolved
| get | ||
| { | ||
| IntPtr handle = _handle; | ||
| GCHandle.ThrowIfInvalid(_handle); |
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.
All these checks should be removed. Using any instance method on an instance that's not allocated is explicitly not supported. As long as we can throw an exception (eg. this should throw NRE) so the behavior is still consistent, that's sufficient.
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.
As long as we can throw an exception (eg. this should throw NRE)
This is the questionable part - the current implementation uses FCall in some cases, and the ability to throw exception from FCall will soon be removed. In other words, no NRE can be thrown, at least for some members.
With that said, providing invalid value via FromIntPtr will still cause hard AV in unmanaged code.
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.
At least for the getter, on CoreCLR and NAOT this should just be *(T*)_handle, which should already throw NRE implicitly.
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.
Maybe an implicit read (_ = *(byte*)value) can be applied with lowest overhead? I'm not worried about garbage value from FromIntPtr, but make new GCHandle<T>{ Target = obj } crashing doesn't look good.
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.
What do you mean by implicit read? You need to read anyway, since you're returning a value. What I'm saying is the whole getter should literally just be get => *(T*)_handle. That will automatically NRE if handle is null, which is all we need.
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 mean adding a read in managed code in setter. Currently the entire setter is executed in unmanaged code and will cause AV, which won't be caught as NRE.
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.
Oh I see what you mean, I thought you were talking about the other accessor. That would seem fine to me, but I'll defer to Jan and others to confirm 🙂
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandleExtensions.cs
Show resolved
Hide resolved
| IntPtr handle = _handle; | ||
| GCHandle.ThrowIfInvalid(handle); | ||
|
|
||
| return GCHandle.AddrOfPinnedObjectFromHandle(_handle); |
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.
Is this expected to follow GCHandle in special casing strings and arrays here?
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.
Memory<T>.Pin and fixed are all following the contract to return the address of first element. Not following the contract would require strong justification.
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 method should be only used for non-array non-string blittable types. Memory<T>.Pin and fixed do not work for non-array non-string blittable types.
I think it would make sense to make it work just for the non-array non-string blittable types and document the behavior as undefined to avoid unnecessary overhead. The overall goal with these new GCHandle types was to eliminate unnecessary overheads.
The original intention with this method was to provide a replacement for GCHandle.AddrOfPinnedObject. I think the method has different enough name to have different behavior.
| #nullable disable // Nullable oblivious because no covariance between PinnedGCHandle<T> and PinnedGCHandle<T?> | ||
| this PinnedGCHandle<T[]> handle) | ||
| #nullable restore | ||
| => (T*)handle.GetAddressOfObjectData(); |
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.
Should those be implemented separately here to avoid runtime checks GCHandle does for performance?
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 point. Yes the check can't be eliminated here.
| /// <param name="target">The object that uses the <see cref="GCHandle{T}"/>.</param> | ||
| public GCHandle(T target) | ||
| { | ||
| _handle = GCHandle.InternalAlloc(target, GCHandleType.Normal); |
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.
Since we rely on IntPtr.Zero elsewhere in the implementation having special meaning, worth asserting here that _handle != IntPtr.Zero?
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.
Should the assert go to InternalAlloc since there are more types depending on this?
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandleExtensions.cs
Show resolved
Hide resolved
src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/PinnedGCHandle.T.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/WeakGCHandle.T.cs
Outdated
Show resolved
Hide resolved
…pServices/PinnedGCHandle.T.cs Co-authored-by: Aaron Robinson <[email protected]>
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/CryptoStream.cs
Outdated
Show resolved
Hide resolved
src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/CryptoStream.cs
Show resolved
Hide resolved
|
Any further review on this? |
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/GCHandle.cs
Show resolved
Hide resolved
jkotas
left a 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.
LGTM. Thank you!
Closes #94134.
IEquatable<T>included.