-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Changed IntPtr's internal value to readonly (and therefore immutable) #18138
Conversation
Should it be a readonly struct then? |
@benaadams Oh yeah! That's a new feature in C# v7.2. |
@@ -23,7 +23,7 @@ public struct IntPtr : IEquatable<IntPtr>, ISerializable | |||
// See https://github.com/dotnet/corert/blob/master/Documentation/design-docs/diagnostics/diagnostics-tools-contract.md for more details. | |||
// Please do not change the type, the name, or the semantic usage of this member without understanding the implication for tools. | |||
// Get in touch with the diagnostics team if you have questions. |
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 you can tell from these comments, the primitive types are treated in special way by tools our there. I wonder what all can break with this change.
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.
Me too. Would the existing automated test suites catch this if it were a breaking change?
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.
The existing tests may not be sufficient to catch the issues. Changes like this introduce new combinations that the existing tests were not designed to exercise.
We have tried to mark Nullable<T>
as readonly. All existing tests were green on the change. But it had to be rolled back because of it was identified as breaking change later. dotnet/corefx#24997 (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.
Interesting! Although it appears System.Nullable may have been a special case.
However, I defer to your more qualified judgement in dropping this PR.
What are the benefits of this change? If this change has any significant benefits, it should be done for all primitive types ( Also, a matching PR needs to be made in corefx to make the same change in contracts. |
… struct and internal value
@jkotas I made the change for all the other primitive types, except Double and Single because their implementation of GetHashCode() passes a reference to the internal value to Unsafe.As(). This change is mostly semantic sugar as it would add an immutable constraint to the internal type. (+1) The field would also be marked initonly in the IL metadata. If the compiler has any optimizations dependent the initonly field, this may unlock an compiler optimization or two. (+1). |
Do you have any real example of optimization that it unlocks? |
@jkotas I don't have any real examples. In fact, I was reviewing the source code to better understand how the backend compiler could optimize away the load for static primitive types (like, address == UIntPtr.Zero). It seems the compiler could reason the load would be unnecessary because in this case UIntPtr.Zero static field is (should be) immutable and a fixed value (zero). In fact, why even store the field in memory when the value must always be zero. Maybe one of the backend compiler gurus can provide some input? |
The JIT does the
|
@jkotas Thanks! I missed that --- I thought [Intrinsic] were only for methods & properties. |
This does actually allow C# to generate more efficient IL in some cases. For example: readonly struct Test
{
public readonly uint x;
static void Method() {
Test x = default;
x.x.ToString();
}
} Without this change, there will be a temp created on the stack that to store the field x. With this change, the temp goes away. |
I think this is interesting change to take. I would like it to be enabled uniformly for all primitive types, including signed types (Int32, Int64, etc.) and floating point types (Single, Double). @tgiphil Are you still interested in working on this? Thank you! |
We can add |
@jkotas Yes, I'd be interested in working on this. I may need help with floating point types (Single, Double) because their implementation of GetHashCode() passes a reference to the internal value to Unsafe.As(). |
@tgiphil, there should be an |
…e, Single, SByte, Int16, Int32, Int64
@jkotas The rest of the primitive types have been updated. The Unsafe.As calls were avoided by using BitConverter.DoubleToInt64Bits and BitConverter.SingleToInt32Bits methods instead. |
What does that do to the GetHashCode performance? |
Also, could you please rebase or merge with current master to resolve the conflicts? |
… struct and internal value
# Conflicts: # src/System.Private.CoreLib/shared/System/Boolean.cs # src/System.Private.CoreLib/shared/System/Byte.cs # src/System.Private.CoreLib/shared/System/Char.cs # src/System.Private.CoreLib/shared/System/UInt16.cs # src/System.Private.CoreLib/shared/System/UInt32.cs # src/System.Private.CoreLib/shared/System/UInt64.cs
The rebase didn't work out as expected. I opened up another PR instead: |
Superseded by #18645 |
No description provided.