Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Changed internal value to readonly for primitive types #18645

Merged
merged 3 commits into from
Jun 27, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,17 @@ public static ref T AsRef<T>(void* source)
return ref Unsafe.As<byte, T>(ref *(byte*)source);
}

/// <summary>
/// Reinterprets the given location as a reference to a value of type <typeparamref name="T"/>.
/// </summary>
[Intrinsic]
[NonVersionable]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ref T AsRef<T>(in T source)
Copy link
Member

@jaredpar jaredpar Jun 27, 2018

Choose a reason for hiding this comment

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

I understand this is in the Unsafe class hence it's unsafe. I want to emphasize though that this operation is not just about violating readonly semantics. It actually can cause some pretty severe safety issues. Consider the following code as an example:

void Example(in object o) { 
  Unsafe.AsRef(in o) = new object(); // really dangerous
}

void M(string[] array) { 
  object[] objArray = array;
  Example(in objArray[0]);
}

Hence this operator allows writing objects that violate our basic type safety into locations. It's not just about violating readonly.

Copy link
Member

Choose a reason for hiding this comment

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

Right. S.R.CS.Unsafe is a very sharp knife that lets introduce pretty severe safety issue if used incorrectly. This particular API shipped already. This change is just adding internal clone of the public API for internal CoreLib consumption.

{
throw new PlatformNotSupportedException();
}

/// <summary>
/// Determines the byte offset from origin to target from the given references.
/// </summary>
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Boolean.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@ namespace System
{
[Serializable]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Boolean : IComparable, IConvertible, IComparable<bool>, IEquatable<bool>
public readonly struct Boolean : IComparable, IConvertible, IComparable<bool>, IEquatable<bool>
{
//
// Member Variables
//
private bool m_value; // Do not rename (binary serialization)
private readonly bool m_value; // Do not rename (binary serialization)

// The true value.
//
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Byte.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace System
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Byte : IComparable, IConvertible, IFormattable, IComparable<byte>, IEquatable<byte>, ISpanFormattable
public readonly struct Byte : IComparable, IConvertible, IFormattable, IComparable<byte>, IEquatable<byte>, ISpanFormattable
{
private byte m_value; // Do not rename (binary serialization)
private readonly byte m_value; // Do not rename (binary serialization)

// The maximum value that a Byte may represent: 255.
public const byte MaxValue = (byte)0xFF;
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Char.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ namespace System
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Char : IComparable, IComparable<char>, IEquatable<char>, IConvertible
public readonly struct Char : IComparable, IComparable<char>, IEquatable<char>, IConvertible
{
//
// Member Variables
//
private char m_value; // Do not rename (binary serialization)
private readonly char m_value; // Do not rename (binary serialization)

//
// Public Constants
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Double.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace System
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Double : IComparable, IConvertible, IFormattable, IComparable<double>, IEquatable<double>, ISpanFormattable
{
private double m_value; // Do not rename (binary serialization)
private readonly double m_value; // Do not rename (binary serialization)

//
// Public Constants
Expand Down Expand Up @@ -226,7 +226,7 @@ public bool Equals(double obj)
[MethodImpl(MethodImplOptions.AggressiveInlining)] // 64-bit constants make the IL unusually large that makes the inliner to reject the method
public override int GetHashCode()
{
var bits = Unsafe.As<double, long>(ref m_value);
var bits = Unsafe.As<double, long>(ref Unsafe.AsRef(in m_value));

// Optimized check for IsNan() || IsZero()
if (((bits - 1) & 0x7FFFFFFFFFFFFFFF) >= 0x7FF0000000000000)
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Int16.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace System
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Int16 : IComparable, IConvertible, IFormattable, IComparable<short>, IEquatable<short>, ISpanFormattable
public readonly struct Int16 : IComparable, IConvertible, IFormattable, IComparable<short>, IEquatable<short>, ISpanFormattable
{
private short m_value; // Do not rename (binary serialization)
private readonly short m_value; // Do not rename (binary serialization)

public const short MaxValue = (short)0x7FFF;
public const short MinValue = unchecked((short)0x8000);
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Int32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace System
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Int32 : IComparable, IConvertible, IFormattable, IComparable<int>, IEquatable<int>, ISpanFormattable
public readonly struct Int32 : IComparable, IConvertible, IFormattable, IComparable<int>, IEquatable<int>, ISpanFormattable
{
private int m_value; // Do not rename (binary serialization)
private readonly int m_value; // Do not rename (binary serialization)

public const int MaxValue = 0x7fffffff;
public const int MinValue = unchecked((int)0x80000000);
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Int64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace System
[Serializable]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Int64 : IComparable, IConvertible, IFormattable, IComparable<long>, IEquatable<long>, ISpanFormattable
public readonly struct Int64 : IComparable, IConvertible, IFormattable, IComparable<long>, IEquatable<long>, ISpanFormattable
{
private long m_value; // Do not rename (binary serialization)
private readonly long m_value; // Do not rename (binary serialization)

public const long MaxValue = 0x7fffffffffffffffL;
public const long MinValue = unchecked((long)0x8000000000000000L);
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/IntPtr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@ namespace System
{
[Serializable]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct IntPtr : IEquatable<IntPtr>, ISerializable
public readonly struct IntPtr : IEquatable<IntPtr>, ISerializable
{
// WARNING: We allow diagnostic tools to directly inspect this member (_value).
// 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.
private unsafe void* _value; // Do not rename (binary serialization)
private readonly unsafe void* _value; // Do not rename (binary serialization)

[Intrinsic]
public static readonly IntPtr Zero;
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/SByte.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ namespace System
[Serializable]
[CLSCompliant(false)] [StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct SByte : IComparable, IConvertible, IFormattable, IComparable<sbyte>, IEquatable<sbyte>, ISpanFormattable
public readonly struct SByte : IComparable, IConvertible, IFormattable, IComparable<sbyte>, IEquatable<sbyte>, ISpanFormattable
{
private sbyte m_value; // Do not rename (binary serialization)
private readonly sbyte m_value; // Do not rename (binary serialization)

// The maximum value that a Byte may represent: 127.
public const sbyte MaxValue = (sbyte)0x7F;
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/Single.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ namespace System
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct Single : IComparable, IConvertible, IFormattable, IComparable<float>, IEquatable<float>, ISpanFormattable
{
private float m_value; // Do not rename (binary serialization)
private readonly float m_value; // Do not rename (binary serialization)

//
// Public constants
Expand Down Expand Up @@ -217,7 +217,7 @@ public bool Equals(float obj)

public override int GetHashCode()
{
var bits = Unsafe.As<float, int>(ref m_value);
var bits = Unsafe.As<float, int>(ref Unsafe.AsRef(in m_value));

// Optimized check for IsNan() || IsZero()
if (((bits - 1) & 0x7FFFFFFF) >= 0x7F800000)
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/UInt16.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ namespace System
[CLSCompliant(false)]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct UInt16 : IComparable, IConvertible, IFormattable, IComparable<ushort>, IEquatable<ushort>, ISpanFormattable
public readonly struct UInt16 : IComparable, IConvertible, IFormattable, IComparable<ushort>, IEquatable<ushort>, ISpanFormattable
{
private ushort m_value; // Do not rename (binary serialization)
private readonly ushort m_value; // Do not rename (binary serialization)

public const ushort MaxValue = (ushort)0xFFFF;
public const ushort MinValue = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/UInt32.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ namespace System
[CLSCompliant(false)]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct UInt32 : IComparable, IConvertible, IFormattable, IComparable<uint>, IEquatable<uint>, ISpanFormattable
public readonly struct UInt32 : IComparable, IConvertible, IFormattable, IComparable<uint>, IEquatable<uint>, ISpanFormattable
{
private uint m_value; // Do not rename (binary serialization)
private readonly uint m_value; // Do not rename (binary serialization)

public const uint MaxValue = (uint)0xffffffff;
public const uint MinValue = 0U;
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/UInt64.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ namespace System
[CLSCompliant(false)]
[StructLayout(LayoutKind.Sequential)]
[TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct UInt64 : IComparable, IConvertible, IFormattable, IComparable<ulong>, IEquatable<ulong>, ISpanFormattable
public readonly struct UInt64 : IComparable, IConvertible, IFormattable, IComparable<ulong>, IEquatable<ulong>, ISpanFormattable
{
private ulong m_value; // Do not rename (binary serialization)
private readonly ulong m_value; // Do not rename (binary serialization)

public const ulong MaxValue = (ulong)0xffffffffffffffffL;
public const ulong MinValue = 0x0;
Expand Down
4 changes: 2 additions & 2 deletions src/System.Private.CoreLib/shared/System/UIntPtr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ namespace System
[Serializable]
[CLSCompliant(false)]
[System.Runtime.CompilerServices.TypeForwardedFrom("mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
public struct UIntPtr : IEquatable<UIntPtr>, ISerializable
public readonly struct UIntPtr : IEquatable<UIntPtr>, ISerializable
{
private unsafe void* _value; // Do not rename (binary serialization)
private readonly unsafe void* _value; // Do not rename (binary serialization)

[Intrinsic]
public static readonly UIntPtr Zero;
Expand Down
3 changes: 2 additions & 1 deletion src/vm/jitinterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7047,7 +7047,8 @@ bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
}
else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef() ||
tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__OBJECT_AS)->GetMemberDef() ||
tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF)->GetMemberDef())
tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_POINTER)->GetMemberDef() ||
tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF_IN)->GetMemberDef())
{
// Return the argument that was passed in.
static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
Expand Down
2 changes: 2 additions & 0 deletions src/vm/metasig.h
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ DEFINE_METASIG(GM(RefByte_T_RetVoid, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, r(b) M(0)
DEFINE_METASIG(GM(PtrVoid_RetT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, P(v), M(0)))
DEFINE_METASIG(GM(PtrVoid_T_RetVoid, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, P(v) M(0), v))

DEFINE_METASIG(GM(RefT_RetRefT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, r(M(0)), r(M(0))))
DEFINE_METASIG(GM(VoidPtr_RetRefT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, P(v), r(M(0))))
DEFINE_METASIG(GM(RefTFrom_RetRefTTo, IMAGE_CEE_CS_CALLCONV_DEFAULT, 2, r(M(0)), r(M(1))))
DEFINE_METASIG(GM(Obj_RetT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, j, M(0)))
DEFINE_METASIG(GM(RefT_Int_RetRefT, IMAGE_CEE_CS_CALLCONV_DEFAULT, 1, r(M(0)) i, r(M(0))))
Expand Down
3 changes: 2 additions & 1 deletion src/vm/mscorlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -775,7 +775,8 @@ DEFINE_METHOD(JIT_HELPERS, GET_RAW_SZ_ARRAY_DATA, GetRawSzArrayData, N

DEFINE_CLASS(UNSAFE, InternalCompilerServices, Unsafe)
DEFINE_METHOD(UNSAFE, AS_POINTER, AsPointer, NoSig)
DEFINE_METHOD(UNSAFE, AS_REF, AsRef, NoSig)
DEFINE_METHOD(UNSAFE, AS_REF_IN, AsRef, GM_RefT_RetRefT)
DEFINE_METHOD(UNSAFE, AS_REF_POINTER, AsRef, GM_VoidPtr_RetRefT)
DEFINE_METHOD(UNSAFE, SIZEOF, SizeOf, NoSig)
DEFINE_METHOD(UNSAFE, BYREF_AS, As, GM_RefTFrom_RetRefTTo)
DEFINE_METHOD(UNSAFE, OBJECT_AS, As, GM_Obj_RetT)
Expand Down