From bafbf1dc53ca89e4885470550ef5bc94ec09f23f Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 18 May 2022 15:17:54 -0700 Subject: [PATCH 01/22] Use C# ref field support Update public APIs --- .../System.Memory/ref/System.Memory.cs | 8 ++-- .../src/System/ReadOnlySpan.cs | 30 +++++++------- .../System/Runtime/CompilerServices/Unsafe.cs | 3 +- .../Runtime/InteropServices/MemoryMarshal.cs | 16 ++++---- .../System.Private.CoreLib/src/System/Span.cs | 40 +++++++++---------- .../src/System/String.cs | 4 +- .../src/System/TypedReference.cs | 2 +- .../System.Runtime/ref/System.Runtime.cs | 2 +- 8 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index 088efa1c8eb81..2ca725c301550 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -542,16 +542,16 @@ public static partial class MemoryMarshal public static System.ReadOnlySpan Cast(System.ReadOnlySpan span) where TFrom : struct where TTo : struct { throw null; } public static System.Span Cast(System.Span span) where TFrom : struct where TTo : struct { throw null; } public static System.Memory CreateFromPinnedArray(T[]? array, int start, int length) { throw null; } - public static System.ReadOnlySpan CreateReadOnlySpan(ref T reference, int length) { throw null; } + public static System.ReadOnlySpan CreateReadOnlySpan(scoped ref T reference, int length) { throw null; } [System.CLSCompliant(false)] public static unsafe ReadOnlySpan CreateReadOnlySpanFromNullTerminated(byte* value) { throw null; } [System.CLSCompliant(false)] public static unsafe ReadOnlySpan CreateReadOnlySpanFromNullTerminated(char* value) { throw null; } - public static System.Span CreateSpan(ref T reference, int length) { throw null; } + public static System.Span CreateSpan(scoped ref T reference, int length) { throw null; } public static ref T GetArrayDataReference(T[] array) { throw null; } public static ref byte GetArrayDataReference(System.Array array) { throw null; } - public static ref T GetReference(System.ReadOnlySpan span) { throw null; } - public static ref T GetReference(System.Span span) { throw null; } + public static ref T GetReference(scoped System.ReadOnlySpan span) { throw null; } + public static ref T GetReference(scoped System.Span span) { throw null; } public static T Read(System.ReadOnlySpan source) where T : struct { throw null; } public static System.Collections.Generic.IEnumerable ToEnumerable(System.ReadOnlyMemory memory) { throw null; } public static bool TryGetArray(System.ReadOnlyMemory memory, out System.ArraySegment segment) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs index 68b2cbc0c2c25..aca4b4f3fec9e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ReadOnlySpan.cs @@ -23,7 +23,7 @@ namespace System public readonly ref struct ReadOnlySpan { /// A byref or a native ptr. - internal readonly ByReference _reference; + internal readonly ref T _reference; /// The number of elements this ReadOnlySpan contains. private readonly int _length; @@ -41,7 +41,7 @@ public ReadOnlySpan(T[]? array) return; // returns default } - _reference = new ByReference(ref MemoryMarshal.GetArrayDataReference(array)); + _reference = ref MemoryMarshal.GetArrayDataReference(array); _length = array.Length; } @@ -75,7 +75,7 @@ public ReadOnlySpan(T[]? array, int start, int length) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - _reference = new ByReference(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */)); + _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */); _length = length; } @@ -102,7 +102,7 @@ public unsafe ReadOnlySpan(void* pointer, int length) if (length < 0) ThrowHelper.ThrowArgumentOutOfRangeException(); - _reference = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); + _reference = ref Unsafe.As(ref *(byte*)pointer); _length = length; } @@ -112,7 +112,7 @@ public unsafe ReadOnlySpan(void* pointer, int length) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal ReadOnlySpan(in T reference) { - _reference = new ByReference(ref Unsafe.AsRef(in reference)); + _reference = ref Unsafe.AsRef(in reference); _length = 1; } @@ -122,7 +122,7 @@ internal ReadOnlySpan(ref T reference, int length) { Debug.Assert(length >= 0); - _reference = new ByReference(ref reference); + _reference = ref reference; _length = length; } @@ -143,7 +143,7 @@ public ref readonly T this[int index] { if ((uint)index >= (uint)_length) ThrowHelper.ThrowIndexOutOfRangeException(); - return ref Unsafe.Add(ref _reference.Value, (nint)(uint)index /* force zero-extension */); + return ref Unsafe.Add(ref _reference, (nint)(uint)index /* force zero-extension */); } } @@ -261,7 +261,7 @@ public ref readonly T GetPinnableReference() { // Ensure that the native code has just one forward branch that is predicted-not-taken. ref T ret = ref Unsafe.NullRef(); - if (_length != 0) ret = ref _reference.Value; + if (_length != 0) ret = ref _reference; return ref ret; } @@ -284,7 +284,7 @@ public void CopyTo(Span destination) if ((uint)_length <= (uint)destination.Length) { - Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length); + Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length); } else { @@ -305,7 +305,7 @@ public bool TryCopyTo(Span destination) bool retVal = false; if ((uint)_length <= (uint)destination.Length) { - Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length); + Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length); retVal = true; } return retVal; @@ -317,7 +317,7 @@ public bool TryCopyTo(Span destination) /// public static bool operator ==(ReadOnlySpan left, ReadOnlySpan right) => left._length == right._length && - Unsafe.AreSame(ref left._reference.Value, ref right._reference.Value); + Unsafe.AreSame(ref left._reference, ref right._reference); /// /// For , returns a new instance of string that represents the characters pointed to by the span. @@ -327,7 +327,7 @@ public override string ToString() { if (typeof(T) == typeof(char)) { - return new string(new ReadOnlySpan(ref Unsafe.As(ref _reference.Value), _length)); + return new string(new ReadOnlySpan(ref Unsafe.As(ref _reference), _length)); } return $"System.ReadOnlySpan<{typeof(T).Name}>[{_length}]"; } @@ -345,7 +345,7 @@ public ReadOnlySpan Slice(int start) if ((uint)start > (uint)_length) ThrowHelper.ThrowArgumentOutOfRangeException(); - return new ReadOnlySpan(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), _length - start); + return new ReadOnlySpan(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), _length - start); } /// @@ -368,7 +368,7 @@ public ReadOnlySpan Slice(int start, int length) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - return new ReadOnlySpan(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), length); + return new ReadOnlySpan(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length); } /// @@ -382,7 +382,7 @@ public T[] ToArray() return Array.Empty(); var destination = new T[_length]; - Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference.Value, (uint)_length); + Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference, (uint)_length); return destination; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs index 2c17b9f4ca3d3..1f2181b9e176c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/Unsafe.cs @@ -665,13 +665,14 @@ public static ref T AsRef(void* source) /// /// Reinterprets the given location as a reference to a value of type . /// + /// The lifetime of the reference will not be validated when using this API. [Intrinsic] // CoreCLR:METHOD__UNSAFE__AS_REF_IN // AOT:AsRef // Mono:AsRef [NonVersionable] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T AsRef(in T source) + public static ref T AsRef(scoped in T source) { throw new PlatformNotSupportedException(); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index 431a8b8c67910..6ef80396c3446 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -77,27 +77,27 @@ public static Memory AsMemory(ReadOnlyMemory memory) => /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(Span span) => ref span._reference.Value; + public static ref T GetReference(scoped Span span) => ref Unsafe.AsRef(in span._reference); /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(ReadOnlySpan span) => ref span._reference.Value; + public static ref T GetReference(scoped ReadOnlySpan span) => ref Unsafe.AsRef(in span._reference); /// /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static unsafe ref T GetNonNullPinnableReference(Span span) => ref (span.Length != 0) ? ref span._reference.Value : ref Unsafe.AsRef((void*)1); + internal static unsafe ref T GetNonNullPinnableReference(scoped Span span) => ref (span.Length != 0) ? ref Unsafe.AsRef(in span._reference) : ref Unsafe.AsRef((void*)1); /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static unsafe ref T GetNonNullPinnableReference(ReadOnlySpan span) => ref (span.Length != 0) ? ref span._reference.Value : ref Unsafe.AsRef((void*)1); + internal static unsafe ref T GetNonNullPinnableReference(scoped ReadOnlySpan span) => ref (span.Length != 0) ? ref Unsafe.AsRef(in span._reference) : ref Unsafe.AsRef((void*)1); /// /// Casts a Span of one primitive type to another primitive type . @@ -150,7 +150,7 @@ public static Span Cast(Span span) } return new Span( - ref Unsafe.As(ref span._reference.Value), + ref Unsafe.As(ref span._reference), toLength); } @@ -219,7 +219,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), /// A span representing the specified reference and length. /// The lifetime of the returned span will not be validated for safety by span-aware languages. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Span CreateSpan(ref T reference, int length) => new Span(ref reference, length); + public static Span CreateSpan(scoped ref T reference, int length) => + new Span(ref Unsafe.AsRef(in reference), length); /// /// Creates a new read-only span over a portion of a regular managed object. This can be useful @@ -231,7 +232,8 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), /// A read-only span representing the specified reference and length. /// The lifetime of the returned span will not be validated for safety by span-aware languages. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan CreateReadOnlySpan(ref T reference, int length) => new ReadOnlySpan(ref reference, length); + public static ReadOnlySpan CreateReadOnlySpan(scoped ref T reference, int length) => + new ReadOnlySpan(ref Unsafe.AsRef(in reference), length); /// Creates a new read-only span for a null-terminated string. /// The pointer to the null-terminated string of characters. diff --git a/src/libraries/System.Private.CoreLib/src/System/Span.cs b/src/libraries/System.Private.CoreLib/src/System/Span.cs index 74c80a8d00132..6ecf1aea753b0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Span.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Span.cs @@ -22,7 +22,7 @@ namespace System public readonly ref struct Span { /// A byref or a native ptr. - internal readonly ByReference _reference; + internal readonly ref T _reference; /// The number of elements this Span contains. private readonly int _length; @@ -43,7 +43,7 @@ public Span(T[]? array) if (!typeof(T).IsValueType && array.GetType() != typeof(T[])) ThrowHelper.ThrowArrayTypeMismatchException(); - _reference = new ByReference(ref MemoryMarshal.GetArrayDataReference(array)); + _reference = ref MemoryMarshal.GetArrayDataReference(array); _length = array.Length; } @@ -80,7 +80,7 @@ public Span(T[]? array, int start, int length) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - _reference = new ByReference(ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */)); + _reference = ref Unsafe.Add(ref MemoryMarshal.GetArrayDataReference(array), (nint)(uint)start /* force zero-extension */); _length = length; } @@ -107,7 +107,7 @@ public unsafe Span(void* pointer, int length) if (length < 0) ThrowHelper.ThrowArgumentOutOfRangeException(); - _reference = new ByReference(ref Unsafe.As(ref *(byte*)pointer)); + _reference = ref Unsafe.As(ref *(byte*)pointer); _length = length; } @@ -117,7 +117,7 @@ public unsafe Span(void* pointer, int length) [MethodImpl(MethodImplOptions.AggressiveInlining)] internal Span(ref T reference) { - _reference = new ByReference(ref reference); + _reference = ref reference; _length = 1; } @@ -127,7 +127,7 @@ internal Span(ref T reference, int length) { Debug.Assert(length >= 0); - _reference = new ByReference(ref reference); + _reference = ref reference; _length = length; } @@ -148,7 +148,7 @@ public ref T this[int index] { if ((uint)index >= (uint)_length) ThrowHelper.ThrowIndexOutOfRangeException(); - return ref Unsafe.Add(ref _reference.Value, (nint)(uint)index /* force zero-extension */); + return ref Unsafe.Add(ref _reference, (nint)(uint)index /* force zero-extension */); } } @@ -266,7 +266,7 @@ public ref T GetPinnableReference() { // Ensure that the native code has just one forward branch that is predicted-not-taken. ref T ret = ref Unsafe.NullRef(); - if (_length != 0) ret = ref _reference.Value; + if (_length != 0) ret = ref _reference; return ref ret; } @@ -278,11 +278,11 @@ public unsafe void Clear() { if (RuntimeHelpers.IsReferenceOrContainsReferences()) { - SpanHelpers.ClearWithReferences(ref Unsafe.As(ref _reference.Value), (uint)_length * (nuint)(Unsafe.SizeOf() / sizeof(nuint))); + SpanHelpers.ClearWithReferences(ref Unsafe.As(ref _reference), (uint)_length * (nuint)(Unsafe.SizeOf() / sizeof(nuint))); } else { - SpanHelpers.ClearWithoutReferences(ref Unsafe.As(ref _reference.Value), (uint)_length * (nuint)Unsafe.SizeOf()); + SpanHelpers.ClearWithoutReferences(ref Unsafe.As(ref _reference), (uint)_length * (nuint)Unsafe.SizeOf()); } } @@ -298,12 +298,12 @@ public void Fill(T value) // The runtime eventually calls memset, which can efficiently support large buffers. // We don't need to check IsReferenceOrContainsReferences because no references // can ever be stored in types this small. - Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _reference.Value), Unsafe.As(ref value), (uint)_length); + Unsafe.InitBlockUnaligned(ref Unsafe.As(ref _reference), Unsafe.As(ref value), (uint)_length); } else { // Call our optimized workhorse method for all other types. - SpanHelpers.Fill(ref _reference.Value, (uint)_length, value); + SpanHelpers.Fill(ref _reference, (uint)_length, value); } } @@ -325,7 +325,7 @@ public void CopyTo(Span destination) if ((uint)_length <= (uint)destination.Length) { - Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length); + Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length); } else { @@ -346,7 +346,7 @@ public bool TryCopyTo(Span destination) bool retVal = false; if ((uint)_length <= (uint)destination.Length) { - Buffer.Memmove(ref destination._reference.Value, ref _reference.Value, (uint)_length); + Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length); retVal = true; } return retVal; @@ -358,13 +358,13 @@ public bool TryCopyTo(Span destination) /// public static bool operator ==(Span left, Span right) => left._length == right._length && - Unsafe.AreSame(ref left._reference.Value, ref right._reference.Value); + Unsafe.AreSame(ref left._reference, ref right._reference); /// /// Defines an implicit conversion of a to a /// public static implicit operator ReadOnlySpan(Span span) => - new ReadOnlySpan(ref span._reference.Value, span._length); + new ReadOnlySpan(ref span._reference, span._length); /// /// For , returns a new instance of string that represents the characters pointed to by the span. @@ -374,7 +374,7 @@ public override string ToString() { if (typeof(T) == typeof(char)) { - return new string(new ReadOnlySpan(ref Unsafe.As(ref _reference.Value), _length)); + return new string(new ReadOnlySpan(ref Unsafe.As(ref _reference), _length)); } return $"System.Span<{typeof(T).Name}>[{_length}]"; } @@ -392,7 +392,7 @@ public Span Slice(int start) if ((uint)start > (uint)_length) ThrowHelper.ThrowArgumentOutOfRangeException(); - return new Span(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), _length - start); + return new Span(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), _length - start); } /// @@ -420,7 +420,7 @@ public Span Slice(int start, int length) ThrowHelper.ThrowArgumentOutOfRangeException(); #endif - return new Span(ref Unsafe.Add(ref _reference.Value, (nint)(uint)start /* force zero-extension */), length); + return new Span(ref Unsafe.Add(ref _reference, (nint)(uint)start /* force zero-extension */), length); } /// @@ -435,7 +435,7 @@ public T[] ToArray() return Array.Empty(); var destination = new T[_length]; - Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference.Value, (uint)_length); + Buffer.Memmove(ref MemoryMarshal.GetArrayDataReference(destination), ref _reference, (uint)_length); return destination; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/String.cs b/src/libraries/System.Private.CoreLib/src/System/String.cs index b52d632ea3022..bffb6e463643d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/String.cs +++ b/src/libraries/System.Private.CoreLib/src/System/String.cs @@ -418,7 +418,7 @@ public void CopyTo(Span destination) { if ((uint)Length <= (uint)destination.Length) { - Buffer.Memmove(ref destination._reference.Value, ref _firstChar, (uint)Length); + Buffer.Memmove(ref destination._reference, ref _firstChar, (uint)Length); } else { @@ -435,7 +435,7 @@ public bool TryCopyTo(Span destination) bool retVal = false; if ((uint)Length <= (uint)destination.Length) { - Buffer.Memmove(ref destination._reference.Value, ref _firstChar, (uint)Length); + Buffer.Memmove(ref destination._reference, ref _firstChar, (uint)Length); retVal = true; } return retVal; diff --git a/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs b/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs index ca25fe9e924c7..01aa69833c5c9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs @@ -83,7 +83,7 @@ public static unsafe object ToObject(TypedReference value) [MethodImpl(MethodImplOptions.InternalCall)] internal static extern unsafe object InternalToObject(void* value); - internal bool IsNull => Unsafe.IsNullRef(ref _value.Value) && _type == IntPtr.Zero; + internal bool IsNull => Unsafe.IsNullRef(ref _value) && _type == IntPtr.Zero; public static Type GetTargetType(TypedReference value) { diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index cb1861d7e74f4..f74bc995d1284 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -11948,7 +11948,7 @@ public static partial class Unsafe public unsafe static void* AsPointer(ref T value) { throw null; } [System.CLSCompliantAttribute(false)] public unsafe static ref T AsRef(void* source) { throw null; } - public static ref T AsRef(in T source) { throw null; } + public static ref T AsRef(scoped in T source) { throw null; } [return: System.Diagnostics.CodeAnalysis.NotNullIfNotNull("o")] public static T? As(object? o) where T : class? { throw null; } public static ref TTo As(ref TFrom source) { throw null; } From 7af11d6700c283a0151e41516af431e91cb5dab2 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 18 May 2022 15:25:27 -0700 Subject: [PATCH 02/22] Update coreclr/vm to remove knowledge of ByReference --- .../src/System/TypedReference.CoreCLR.cs | 2 +- src/coreclr/inc/dacvars.h | 1 - src/coreclr/vm/appdomain.cpp | 6 -- src/coreclr/vm/classnames.h | 1 - src/coreclr/vm/corelib.h | 4 +- src/coreclr/vm/interpreter.cpp | 76 ------------------- src/coreclr/vm/interpreter.h | 2 - src/coreclr/vm/jitinterface.cpp | 14 ---- src/coreclr/vm/methodtable.cpp | 21 +---- src/coreclr/vm/methodtablebuilder.cpp | 7 -- src/coreclr/vm/mlinfo.cpp | 2 - src/coreclr/vm/siginfo.cpp | 6 -- src/coreclr/vm/tailcallhelp.cpp | 43 +++-------- src/coreclr/vm/vars.cpp | 1 - src/coreclr/vm/vars.hpp | 1 - 15 files changed, 15 insertions(+), 172 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs index 3698bf8365fde..abfc338dba509 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs @@ -9,7 +9,7 @@ namespace System [System.Runtime.Versioning.NonVersionable] // This only applies to field layout public ref partial struct TypedReference { - private readonly ByReference _value; + private readonly ref byte _value; private readonly IntPtr _type; } } diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h index 68ec3af418f00..5ce668353c4fb 100644 --- a/src/coreclr/inc/dacvars.h +++ b/src/coreclr/inc/dacvars.h @@ -163,7 +163,6 @@ DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pStringClass, ::g_pStringClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pArrayClass, ::g_pArrayClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pSZArrayHelperClass, ::g_pSZArrayHelperClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pNullableClass, ::g_pNullableClass) -DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pByReferenceClass, ::g_pByReferenceClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pExceptionClass, ::g_pExceptionClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pThreadAbortExceptionClass, ::g_pThreadAbortExceptionClass) DEFINE_DACVAR(UNKNOWN_POINTER_TYPE, dac__g_pOutOfMemoryExceptionClass, ::g_pOutOfMemoryExceptionClass) diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index f83fa90ee6072..e61c6cb4a9dc0 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -1361,12 +1361,6 @@ void SystemDomain::LoadBaseSystemClasses() // the SZArrayHelper class here. g_pSZArrayHelperClass = CoreLibBinder::GetClass(CLASS__SZARRAYHELPER); - // Load ByReference class - // - // NOTE: ByReference must be the first by-ref-like system type to be loaded, - // because MethodTable::ClassifyEightBytesWithManagedLayout depends on it. - g_pByReferenceClass = CoreLibBinder::GetClass(CLASS__BYREFERENCE); - // Load Nullable class g_pNullableClass = CoreLibBinder::GetClass(CLASS__NULLABLE); diff --git a/src/coreclr/vm/classnames.h b/src/coreclr/vm/classnames.h index 7d71ce2c7d891..61e57e3ef5473 100644 --- a/src/coreclr/vm/classnames.h +++ b/src/coreclr/vm/classnames.h @@ -15,7 +15,6 @@ #define g_ArrayClassName "System.Array" #define g_NullableName "Nullable`1" -#define g_ByReferenceName "ByReference`1" #define g_CollectionsEnumerableItfName "System.Collections.IEnumerable" #define g_CollectionsEnumeratorClassName "System.Collections.IEnumerator" diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index 5d02b0881d563..eb14db4fd9938 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -572,9 +572,9 @@ DEFINE_FIELD(NULL, VALUE, Value) DEFINE_CLASS(NULLABLE, System, Nullable`1) -DEFINE_CLASS(BYREFERENCE, System, ByReference`1) +DEFINE_CLASS(BYREFERENCE, System, ByReference) DEFINE_METHOD(BYREFERENCE, CTOR, .ctor, NoSig) -DEFINE_METHOD(BYREFERENCE, GET_VALUE, get_Value, NoSig) +DEFINE_FIELD(BYREFERENCE, VALUE, Value) DEFINE_CLASS(SPAN, System, Span`1) DEFINE_METHOD(SPAN, CTOR_PTR_INT, .ctor, IM_VoidPtr_Int_RetVoid) DEFINE_METHOD(SPAN, GET_ITEM, get_Item, IM_Int_RetRefT) diff --git a/src/coreclr/vm/interpreter.cpp b/src/coreclr/vm/interpreter.cpp index 0200c71a4887b..5e6d3e9f85cac 100644 --- a/src/coreclr/vm/interpreter.cpp +++ b/src/coreclr/vm/interpreter.cpp @@ -9177,14 +9177,6 @@ void Interpreter::DoCallWork(bool virtualCall, void* thisArg, CORINFO_RESOLVED_T { switch (intrinsicId) { - case NI_System_ByReference_ctor: - DoByReferenceCtor(); - didIntrinsic = true; - break; - case NI_System_ByReference_get_Value: - DoByReferenceValue(); - didIntrinsic = true; - break; #if INTERP_ILSTUBS case NI_System_StubHelpers_GetStubContext: OpStackSet(m_curStackHt, GetStubContext()); @@ -10752,74 +10744,6 @@ void Interpreter::DoGetTypeFromHandle() OpStackTypeSet(ind, InterpreterType(CORINFO_TYPE_CLASS)); } -void Interpreter::DoByReferenceCtor() -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - // Note 'this' is not passed on the operand stack... - _ASSERTE(m_curStackHt > 0); - _ASSERTE(m_callThisArg != NULL); - unsigned valInd = m_curStackHt - 1; - CorInfoType valCit = OpStackTypeGet(valInd).ToCorInfoType(); - -#ifdef _DEBUG - if (valCit != CORINFO_TYPE_BYREF) - { - VerificationError("ByReference.ctor called with non-byref value."); - } -#endif // _DEBUG - -#if INTERP_TRACING - if (s_TraceInterpreterILFlag.val(CLRConfig::INTERNAL_TraceInterpreterIL)) - { - fprintf(GetLogFile(), " ByReference.ctor -- intrinsic\n"); - } -#endif // INTERP_TRACING - - GCX_FORBID(); - void** thisPtr = reinterpret_cast(m_callThisArg); - void* val = OpStackGet(valInd); - *thisPtr = val; - m_curStackHt--; -} - -void Interpreter::DoByReferenceValue() -{ - CONTRACTL { - THROWS; - GC_TRIGGERS; - MODE_COOPERATIVE; - } CONTRACTL_END; - - _ASSERTE(m_curStackHt > 0); - unsigned slot = m_curStackHt - 1; - CorInfoType thisCit = OpStackTypeGet(slot).ToCorInfoType(); - -#ifdef _DEBUG - if (thisCit != CORINFO_TYPE_BYREF) - { - VerificationError("ByReference.get_Value called with non-byref this"); - } -#endif // _DEBUG - -#if INTERP_TRACING - if (s_TraceInterpreterILFlag.val(CLRConfig::INTERNAL_TraceInterpreterIL)) - { - fprintf(GetLogFile(), " ByReference.getValue -- intrinsic\n"); - } -#endif // INTERP_TRACING - - GCX_FORBID(); - void** thisPtr = OpStackGet(slot); - void* value = *thisPtr; - OpStackSet(slot, value); - OpStackTypeSet(slot, InterpreterType(CORINFO_TYPE_BYREF)); -} - void Interpreter::DoSIMDHwAccelerated() { CONTRACTL { diff --git a/src/coreclr/vm/interpreter.h b/src/coreclr/vm/interpreter.h index 7856f97fbeba8..517cb554bd3ed 100644 --- a/src/coreclr/vm/interpreter.h +++ b/src/coreclr/vm/interpreter.h @@ -1774,8 +1774,6 @@ class Interpreter void DoStringLength(); void DoStringGetChar(); void DoGetTypeFromHandle(); - void DoByReferenceCtor(); - void DoByReferenceValue(); void DoSIMDHwAccelerated(); void DoGetIsSupported(); diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 5e8244137075d..6883c7e0cfbde 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -2067,9 +2067,6 @@ static unsigned ComputeGCLayout(MethodTable * pMT, BYTE* gcPtrs) _ASSERTE(pMT->IsValueType()); - if (pMT->HasSameTypeDefAs(g_pByReferenceClass)) - return MarkGCField(gcPtrs, TYPE_GC_BYREF); - unsigned result = 0; ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS); for (FieldDesc *pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next()) @@ -9168,17 +9165,6 @@ CorInfoType CEEInfo::getFieldTypeInternal (CORINFO_FIELD_HANDLE fieldHnd, TypeHandle clsHnd = TypeHandle(); FieldDesc* field = (FieldDesc*) fieldHnd; CorElementType type = field->GetFieldType(); - - if (type == ELEMENT_TYPE_I) - { - PTR_MethodTable enclosingMethodTable = field->GetApproxEnclosingMethodTable(); - if (enclosingMethodTable->IsByRefLike() && enclosingMethodTable->HasSameTypeDefAs(g_pByReferenceClass)) - { - _ASSERTE(field->GetOffset() == 0); - return CORINFO_TYPE_BYREF; - } - } - if (!CorTypeInfo::IsPrimitiveType(type)) { PCCOR_SIGNATURE sig; diff --git a/src/coreclr/vm/methodtable.cpp b/src/coreclr/vm/methodtable.cpp index 1814ff4de269c..4b2215f4c9be2 100644 --- a/src/coreclr/vm/methodtable.cpp +++ b/src/coreclr/vm/methodtable.cpp @@ -2285,12 +2285,6 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi numIntroducedFields = GetNumInstanceFieldBytes() / pFieldStart->GetSize(); } - // System types are loaded before others, so ByReference would be loaded before Span or any other type that has a - // ByReference field. ByReference is the first by-ref-like system type to be loaded (see - // SystemDomain::LoadBaseSystemClasses), so if the current method table is marked as by-ref-like and g_pByReferenceClass is - // null, it must be the initial load of ByReference. - bool isThisByReferenceOfT = IsByRefLike() && (g_pByReferenceClass == nullptr || HasSameTypeDefAs(g_pByReferenceClass)); - for (unsigned int fieldIndex = 0; fieldIndex < numIntroducedFields; fieldIndex++) { FieldDesc* pField; @@ -2320,20 +2314,7 @@ bool MethodTable::ClassifyEightBytesWithManagedLayout(SystemVStructRegisterPassi } CorElementType fieldType = pField->GetFieldType(); - - SystemVClassificationType fieldClassificationType; - if (isThisByReferenceOfT) - { - // ByReference is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC - // memory, so classify its field as such - _ASSERTE(numIntroducedFields == 1); - _ASSERTE(fieldType == CorElementType::ELEMENT_TYPE_I); - fieldClassificationType = SystemVClassificationTypeIntegerByRef; - } - else - { - fieldClassificationType = CorInfoType2UnixAmd64Classification(fieldType); - } + SystemVClassificationType fieldClassificationType = CorInfoType2UnixAmd64Classification(fieldType); #ifdef _DEBUG LPCUTF8 fieldName; diff --git a/src/coreclr/vm/methodtablebuilder.cpp b/src/coreclr/vm/methodtablebuilder.cpp index bb330ee8654cd..f6e8027d608db 100644 --- a/src/coreclr/vm/methodtablebuilder.cpp +++ b/src/coreclr/vm/methodtablebuilder.cpp @@ -8816,10 +8816,6 @@ MethodTableBuilder::HandleExplicitLayout( STANDARD_VM_CONTRACT; _ASSERTE(pMT->IsByRefLike()); - // ByReference is an indication for a byref field, treat it as such. - if (pMT->HasSameTypeDefAs(g_pByReferenceClass)) - return MarkTagType(pFieldLayout, TARGET_POINTER_SIZE, byref); - ExplicitClassTrust explicitClassTrust; ExplicitFieldTrust::TrustLevel trust; @@ -9902,9 +9898,6 @@ void MethodTableBuilder::CheckForSystemTypes() if (g_pNullableClass != NULL) { - _ASSERTE(g_pByReferenceClass != NULL); - _ASSERTE(g_pByReferenceClass->IsByRefLike()); - _ASSERTE(g_pNullableClass->IsNullable()); // Pre-compute whether the class is a Nullable so that code:Nullable::IsNullableType is efficient diff --git a/src/coreclr/vm/mlinfo.cpp b/src/coreclr/vm/mlinfo.cpp index 471cbb1165aaf..b8ad72d5134f6 100644 --- a/src/coreclr/vm/mlinfo.cpp +++ b/src/coreclr/vm/mlinfo.cpp @@ -2263,7 +2263,6 @@ MarshalInfo::MarshalInfo(Module* pModule, break; // Blittable generics are allowed to be marshalled with the following exceptions: - // * ByReference: This represents an interior pointer and is not actually blittable // * Nullable: We don't want to be locked into the default behavior as we may want special handling later // * Vector64: Represents the __m64 ABI primitive which requires currently unimplemented handling // * Vector128: Represents the __m128 ABI primitive which requires currently unimplemented handling @@ -2273,7 +2272,6 @@ MarshalInfo::MarshalInfo(Module* pModule, if (m_pMT->HasInstantiation() && !IsFieldScenario() && (!m_pMT->IsBlittable() || (m_pMT->HasSameTypeDefAs(g_pNullableClass) - || m_pMT->HasSameTypeDefAs(g_pByReferenceClass) || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__SPAN)) || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__READONLY_SPAN)) || m_pMT->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__VECTOR64T)) diff --git a/src/coreclr/vm/siginfo.cpp b/src/coreclr/vm/siginfo.cpp index e5b108ac7ca47..d0d82eefcb7cf 100644 --- a/src/coreclr/vm/siginfo.cpp +++ b/src/coreclr/vm/siginfo.cpp @@ -4936,12 +4936,6 @@ class ByRefPointerOffsetsReporter _ASSERTE(pMT != nullptr); _ASSERTE(pMT->IsByRefLike()); - if (pMT->HasSameTypeDefAs(g_pByReferenceClass)) - { - Report(baseOffset); - return; - } - ApproxFieldDescIterator fieldIterator(pMT, ApproxFieldDescIterator::INSTANCE_FIELDS); for (FieldDesc* pFD = fieldIterator.Next(); pFD != NULL; pFD = fieldIterator.Next()) { diff --git a/src/coreclr/vm/tailcallhelp.cpp b/src/coreclr/vm/tailcallhelp.cpp index caa6cf4e6f64e..522528a0ee3e1 100644 --- a/src/coreclr/vm/tailcallhelp.cpp +++ b/src/coreclr/vm/tailcallhelp.cpp @@ -630,49 +630,28 @@ void TailCallHelp::CreateCallTargetStubSig(const TailCallInfo& info, SigBuilder* #endif // _DEBUG } -// Get TypeHandle for ByReference -static TypeHandle GetByReferenceOfByteType() +static TypeHandle GetByReferenceType() { - TypeHandle byteTH(CoreLibBinder::GetElementType(ELEMENT_TYPE_U1)); - Instantiation byteInst(&byteTH, 1); - TypeHandle th = TypeHandle(CoreLibBinder::GetClass(CLASS__BYREFERENCE)).Instantiate(byteInst); + TypeHandle th = TypeHandle(CoreLibBinder::GetClass(CLASS__BYREFERENCE)); return th; } -// Get MethodDesc* for ByReference::get_Value -static MethodDesc* GetByReferenceOfByteValueGetter() +static FieldDesc* GetByReferenceValueField() { - MethodDesc* getter = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__GET_VALUE); - getter = - MethodDesc::FindOrCreateAssociatedMethodDesc( - getter, - GetByReferenceOfByteType().GetMethodTable(), - false, - Instantiation(), - TRUE); - - return getter; + FieldDesc* pFD = CoreLibBinder::GetField(FIELD__BYREFERENCE__VALUE); + return pFD; } -// Get MethodDesc* for ByReference::.ctor -static MethodDesc* GetByReferenceOfByteCtor() +static MethodDesc* GetByReferenceOfCtor() { - MethodDesc* ctor = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__CTOR); - ctor = - MethodDesc::FindOrCreateAssociatedMethodDesc( - ctor, - GetByReferenceOfByteType().GetMethodTable(), - false, - Instantiation(), - TRUE); - - return ctor; + MethodDesc* pMD = CoreLibBinder::GetMethod(METHOD__BYREFERENCE__CTOR); + return pMD; } void TailCallHelp::EmitLoadTyHnd(ILCodeStream* stream, TypeHandle tyHnd) { if (tyHnd.IsByRef()) - stream->EmitCALL(stream->GetToken(GetByReferenceOfByteValueGetter()), 1, 1); + stream->EmitLDFLD(stream->GetToken(GetByReferenceValueField())); else stream->EmitLDOBJ(stream->GetToken(tyHnd)); } @@ -681,8 +660,8 @@ void TailCallHelp::EmitStoreTyHnd(ILCodeStream* stream, TypeHandle tyHnd) { if (tyHnd.IsByRef()) { - stream->EmitNEWOBJ(stream->GetToken(GetByReferenceOfByteCtor()), 1); - stream->EmitSTOBJ(stream->GetToken(GetByReferenceOfByteType())); + stream->EmitNEWOBJ(stream->GetToken(GetByReferenceOfCtor()), 1); + stream->EmitSTOBJ(stream->GetToken(GetByReferenceType())); } else { diff --git a/src/coreclr/vm/vars.cpp b/src/coreclr/vm/vars.cpp index a796d58ef99a5..d725b6f4c4f06 100644 --- a/src/coreclr/vm/vars.cpp +++ b/src/coreclr/vm/vars.cpp @@ -57,7 +57,6 @@ GPTR_IMPL(MethodTable, g_pStringClass); GPTR_IMPL(MethodTable, g_pArrayClass); GPTR_IMPL(MethodTable, g_pSZArrayHelperClass); GPTR_IMPL(MethodTable, g_pNullableClass); -GPTR_IMPL(MethodTable, g_pByReferenceClass); GPTR_IMPL(MethodTable, g_pExceptionClass); GPTR_IMPL(MethodTable, g_pThreadAbortExceptionClass); GPTR_IMPL(MethodTable, g_pOutOfMemoryExceptionClass); diff --git a/src/coreclr/vm/vars.hpp b/src/coreclr/vm/vars.hpp index 032e062c59109..d7e1ffee509c7 100644 --- a/src/coreclr/vm/vars.hpp +++ b/src/coreclr/vm/vars.hpp @@ -363,7 +363,6 @@ GPTR_DECL(MethodTable, g_pStringClass); GPTR_DECL(MethodTable, g_pArrayClass); GPTR_DECL(MethodTable, g_pSZArrayHelperClass); GPTR_DECL(MethodTable, g_pNullableClass); -GPTR_DECL(MethodTable, g_pByReferenceClass); GPTR_DECL(MethodTable, g_pExceptionClass); GPTR_DECL(MethodTable, g_pThreadAbortExceptionClass); GPTR_DECL(MethodTable, g_pOutOfMemoryExceptionClass); From b39eaa7175f6dc67dd6d30333dfc5b8a50712bbe Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 18 May 2022 15:26:06 -0700 Subject: [PATCH 03/22] Update coreclr/jit to remove ByReference intrinsics --- src/coreclr/jit/importer.cpp | 42 ---------------------------- src/coreclr/jit/namedintrinsiclist.h | 2 -- 2 files changed, 44 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index e2360e7f7c80d..c434f924cd376 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -3846,8 +3846,6 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, break; case NI_Internal_Runtime_MethodTable_Of: - case NI_System_ByReference_ctor: - case NI_System_ByReference_get_Value: case NI_System_Activator_AllocatorOf: case NI_System_Activator_DefaultConstructorOf: case NI_System_EETypePtr_EETypePtrOf: @@ -3953,35 +3951,6 @@ GenTree* Compiler::impIntrinsic(GenTree* newobjThis, break; } - // Implement ByReference Ctor. This wraps the assignment of the ref into a byref-like field - // in a value type. The canonical example of this is Span. In effect this is just a - // substitution. The parameter byref will be assigned into the newly allocated object. - case NI_System_ByReference_ctor: - { - // Remove call to constructor and directly assign the byref passed - // to the call to the first slot of the ByReference struct. - GenTree* op1 = impPopStack().val; - GenTree* thisptr = newobjThis; - CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0); - GenTree* field = gtNewFieldRef(TYP_BYREF, fldHnd, thisptr, 0); - GenTree* assign = gtNewAssignNode(field, op1); - GenTree* byReferenceStruct = gtCloneExpr(thisptr->gtGetOp1()); - assert(byReferenceStruct != nullptr); - impPushOnStack(byReferenceStruct, typeInfo(TI_STRUCT, clsHnd)); - retNode = assign; - break; - } - - // Implement ptr value getter for ByReference struct. - case NI_System_ByReference_get_Value: - { - GenTree* op1 = impPopStack().val; - CORINFO_FIELD_HANDLE fldHnd = info.compCompHnd->getFieldInClass(clsHnd, 0); - GenTree* field = gtNewFieldRef(TYP_BYREF, fldHnd, op1, 0); - retNode = field; - break; - } - case NI_System_Runtime_CompilerServices_RuntimeHelpers_CreateSpan: { retNode = impCreateSpanIntrinsic(sig); @@ -5452,17 +5421,6 @@ NamedIntrinsic Compiler::lookupNamedIntrinsic(CORINFO_METHOD_HANDLE method) result = NI_System_Activator_DefaultConstructorOf; } } - else if (strcmp(className, "ByReference`1") == 0) - { - if (strcmp(methodName, ".ctor") == 0) - { - result = NI_System_ByReference_ctor; - } - else if (strcmp(methodName, "get_Value") == 0) - { - result = NI_System_ByReference_get_Value; - } - } else if (strcmp(className, "Math") == 0 || strcmp(className, "MathF") == 0) { if (strcmp(methodName, "Abs") == 0) diff --git a/src/coreclr/jit/namedintrinsiclist.h b/src/coreclr/jit/namedintrinsiclist.h index c206a8c90cc7e..ca812ab66e311 100644 --- a/src/coreclr/jit/namedintrinsiclist.h +++ b/src/coreclr/jit/namedintrinsiclist.h @@ -76,8 +76,6 @@ enum NamedIntrinsic : unsigned short NI_Array_Get, NI_Array_Set, - NI_System_ByReference_ctor, - NI_System_ByReference_get_Value, NI_System_Activator_AllocatorOf, NI_System_Activator_DefaultConstructorOf, NI_System_EETypePtr_EETypePtrOf, From bcb19b466d296a1615e9c5dcc3271ad7ce95f4f4 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 18 May 2022 15:27:00 -0700 Subject: [PATCH 04/22] Create new ByReference to be used in Reflection and tailcall slow paths --- .../src/System/ByReference.cs | 34 ++++--------------- .../src/System/Reflection/MethodBase.cs | 16 ++++----- 2 files changed, 14 insertions(+), 36 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/ByReference.cs b/src/libraries/System.Private.CoreLib/src/System/ByReference.cs index bb58fc3579a45..230a854d6d1f3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/ByReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/ByReference.cs @@ -6,36 +6,14 @@ namespace System { - // ByReference is meant to be used to represent "ref T" fields. It is working - // around lack of first class support for byref fields in C# and IL. The JIT and - // type loader has special handling for it that turns it into a thin wrapper around ref T. + // ByReference is meant to be used to represent a tracked reference in cases where C# + // proves difficult. See use in Reflection. [NonVersionable] - internal readonly ref struct ByReference + internal readonly ref struct ByReference { -#pragma warning disable CA1823, 169 // private field '{blah}' is never used - private readonly IntPtr _value; -#pragma warning restore CA1823, 169 + public readonly ref byte Value; + public ByReference(ref byte value) => Value = ref value; -#pragma warning disable IDE0060 - [Intrinsic] - public ByReference(ref T value) - { - // Implemented as a JIT intrinsic - This default implementation is for - // completeness and to provide a concrete error if called via reflection - // or if intrinsic is missed. - throw new PlatformNotSupportedException(); - } -#pragma warning restore IDE0060 - -#pragma warning disable CA1822 // Mark members as static - public ref T Value - { - // Implemented as a JIT intrinsic - This default implementation is for - // completeness and to provide a concrete error if called via reflection - // or if the intrinsic is missed. - [Intrinsic] - get => throw new PlatformNotSupportedException(); - } -#pragma warning restore CA1822 + public static ByReference Create(ref T p) => new ByReference(ref Unsafe.As(ref p)); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs index 3053aab008a49..374ddbf1a357c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/MethodBase.cs @@ -220,13 +220,13 @@ BindingFlags invokeAttr // Once Mono has managed conversion logic, VerifyValueType() can be lifted here as Asserts. sigType.VerifyValueType(arg); #endif - ByReference valueTypeRef = new(ref copyOfParameters[i]!.GetRawData()); - *(ByReference*)(byrefParameters + i) = valueTypeRef; + ByReference valueTypeRef = ByReference.Create(ref copyOfParameters[i]!.GetRawData()); + *(ByReference*)(byrefParameters + i) = valueTypeRef; } else { - ByReference objRef = new(ref copyOfParameters[i]); - *(ByReference*)(byrefParameters + i) = objRef; + ByReference objRef = ByReference.Create(ref copyOfParameters[i]); + *(ByReference*)(byrefParameters + i) = objRef; } } } @@ -259,11 +259,11 @@ private protected ref struct StackAllocedArguments [StructLayout(LayoutKind.Sequential)] private protected ref struct StackAllocatedByRefs { - internal ByReference _arg0; + internal ref byte _arg0; #pragma warning disable CA1823, CS0169, IDE0051 // accessed via 'CheckArguments' ref arithmetic - private ByReference _arg1; - private ByReference _arg2; - private ByReference _arg3; + private ref byte _arg1; + private ref byte _arg2; + private ref byte _arg3; #pragma warning restore CA1823, CS0169, IDE0051 } #endif From 0ffd2dc2577bb984b96d075469a1fb56bb7290a2 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 18 May 2022 15:27:57 -0700 Subject: [PATCH 05/22] Remove ByReference from crossgen/aot code base --- .../src/System/TypedReference.cs | 6 ++-- .../tools/Common/JitInterface/CorInfoImpl.cs | 14 ---------- .../SystemVStructClassificator.cs | 28 +++++-------------- .../Common/ExplicitLayoutValidator.cs | 2 +- .../Common/MetadataTypeSystemContext.cs | 5 ++-- .../Common/TypeSystem/Common/TypeDesc.cs | 13 --------- .../Common/TypeSystem/Common/WellKnownType.cs | 1 - .../TypeSystem/Interop/IL/MarshalHelpers.cs | 2 -- .../Common/TypeSystem/Interop/InteropTypes.cs | 5 ---- .../IL/ILImporter.Scanner.cs | 5 ---- .../ReadyToRun/GCRefMapBuilder.cs | 14 +++++----- .../ReadyToRunMetadataFieldLayoutAlgorithm.cs | 2 +- .../CoreTestAssembly/InstanceFieldLayout.cs | 2 +- .../CoreTestAssembly/Platform.cs | 6 ++-- .../ILTestAssembly/InstanceFieldLayout.il | 8 +++--- .../InstanceFieldLayoutTests.cs | 9 ++---- .../tools/dotnet-pgo/dotnet-pgo.csproj | 3 ++ 17 files changed, 33 insertions(+), 92 deletions(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypedReference.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypedReference.cs index cb0878884a8ee..5385e5e58c58b 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypedReference.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/TypedReference.cs @@ -16,12 +16,12 @@ namespace System public ref struct TypedReference { // Do not change the ordering of these fields. The JIT has a dependency on this layout. - private readonly ByReference _value; + private readonly ref byte _value; private readonly RuntimeTypeHandle _typeHandle; private TypedReference(object target, int offset, RuntimeTypeHandle typeHandle) { - _value = new ByReference(ref Unsafe.Add(ref target.GetRawData(), offset)); + _value = ref Unsafe.Add(ref target.GetRawData(), offset); _typeHandle = typeHandle; } @@ -81,7 +81,7 @@ internal ref byte Value [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - return ref _value.Value; + return ref _value; } } } diff --git a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs index a657279bfd1b1..5b3c5cabef79f 100644 --- a/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs +++ b/src/coreclr/tools/Common/JitInterface/CorInfoImpl.cs @@ -2236,11 +2236,6 @@ private int GatherClassGCLayout(TypeDesc type, byte* gcPtrs) { int result = 0; - if (type.IsByReferenceOfT) - { - return MarkGcField(gcPtrs, CorInfoGCType.TYPE_GC_BYREF); - } - foreach (var field in type.GetFields()) { if (field.IsStatic) @@ -2859,15 +2854,6 @@ private CorInfoType getFieldType(CORINFO_FIELD_STRUCT_* field, CORINFO_CLASS_STR type = asCorInfoType(fieldType); } - Debug.Assert(!fieldDesc.OwningType.IsByReferenceOfT || - fieldDesc.OwningType.GetKnownField("_value").FieldType.Category == TypeFlags.IntPtr); - if (type == CorInfoType.CORINFO_TYPE_NATIVEINT && fieldDesc.OwningType.IsByReferenceOfT) - { - Debug.Assert(structType == null || *structType == null); - Debug.Assert(fieldDesc.Offset.AsInt == 0); - type = CorInfoType.CORINFO_TYPE_BYREF; - } - return type; } diff --git a/src/coreclr/tools/Common/JitInterface/SystemVStructClassificator.cs b/src/coreclr/tools/Common/JitInterface/SystemVStructClassificator.cs index c4105d1ce9173..9d6e75dcd1008 100644 --- a/src/coreclr/tools/Common/JitInterface/SystemVStructClassificator.cs +++ b/src/coreclr/tools/Common/JitInterface/SystemVStructClassificator.cs @@ -30,7 +30,7 @@ internal SystemVStructRegisterPassingHelper(int totalStructSize) FieldClassifications = new SystemVClassificationType[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; FieldSizes = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; FieldOffsets = new int[SYSTEMV_MAX_NUM_FIELDS_IN_REGISTER_PASSED_STRUCT]; - + for (int i = 0; i < CLR_SYSTEMV_MAX_EIGHTBYTES_COUNT_TO_PASS_IN_REGISTERS; i++) { EightByteClassifications[i] = SystemVClassificationTypeNoClass; @@ -94,7 +94,7 @@ public static void GetSystemVAmd64PassStructInRegisterDescriptor(TypeDesc typeDe { structPassInRegDescPtr = default; structPassInRegDescPtr.passedInRegisters = false; - + int typeSize = typeDesc.GetElementSize().AsInt; if (typeDesc.IsValueType && (typeSize <= CLR_SYSTEMV_MAX_STRUCT_BYTES_TO_PASS_IN_REGISTERS)) { @@ -114,7 +114,7 @@ public static void GetSystemVAmd64PassStructInRegisterDescriptor(TypeDesc typeDe structPassInRegDescPtr.eightByteClassifications0 = helper.EightByteClassifications[0]; structPassInRegDescPtr.eightByteSizes0 = (byte)helper.EightByteSizes[0]; structPassInRegDescPtr.eightByteOffsets0 = (byte)helper.EightByteOffsets[0]; - + structPassInRegDescPtr.eightByteClassifications1 = helper.EightByteClassifications[1]; structPassInRegDescPtr.eightByteSizes1 = (byte)helper.EightByteSizes[1]; structPassInRegDescPtr.eightByteOffsets1 = (byte)helper.EightByteOffsets[1]; @@ -216,7 +216,7 @@ static SystemVClassificationType ReClassifyField(SystemVClassificationType origi /// /// Returns 'true' if the struct is passed in registers, 'false' otherwise. /// - private static bool ClassifyEightBytes(TypeDesc typeDesc, + private static bool ClassifyEightBytes(TypeDesc typeDesc, ref SystemVStructRegisterPassingHelper helper, int startOffsetOfStruct) { @@ -294,21 +294,7 @@ private static bool ClassifyEightBytes(TypeDesc typeDesc, return false; } - SystemVClassificationType fieldClassificationType; - if (typeDesc.IsByReferenceOfT) - { - // ByReference is a special type whose single IntPtr field holds a by-ref potentially interior pointer to GC - // memory, so classify its field as such - Debug.Assert(numIntroducedFields == 1); - Debug.Assert(field.FieldType.IsWellKnownType(WellKnownType.IntPtr)); - - fieldClassificationType = SystemVClassificationTypeIntegerByRef; - } - else - { - fieldClassificationType = TypeDef2SystemVClassification(field.FieldType); - } - + SystemVClassificationType fieldClassificationType = TypeDef2SystemVClassification(field.FieldType); if (fieldClassificationType == SystemVClassificationTypeStruct) { bool inEmbeddedStructPrev = helper.InEmbeddedStruct; @@ -316,7 +302,7 @@ private static bool ClassifyEightBytes(TypeDesc typeDesc, bool structRet = false; structRet = ClassifyEightBytes(field.FieldType, ref helper, normalizedFieldOffset); - + helper.InEmbeddedStruct = inEmbeddedStructPrev; if (!structRet) @@ -482,7 +468,7 @@ private static void AssignClassifiedEightByteTypes(ref SystemVStructRegisterPass else if ((helper.EightByteClassifications[currentFieldEightByte] == SystemVClassificationTypeInteger) || (fieldClassificationType == SystemVClassificationTypeInteger)) { - Debug.Assert((fieldClassificationType != SystemVClassificationTypeIntegerReference) && + Debug.Assert((fieldClassificationType != SystemVClassificationTypeIntegerReference) && (fieldClassificationType != SystemVClassificationTypeIntegerByRef)); helper.EightByteClassifications[currentFieldEightByte] = SystemVClassificationTypeInteger; diff --git a/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs b/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs index 2decce4fa7421..e8b7327ecd2f3 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/ExplicitLayoutValidator.cs @@ -157,7 +157,7 @@ private void MarkByRefAndORefLocations(MetadataType type, List WellKnownTypeNames => s_wellKnownTypeNames; @@ -71,7 +70,7 @@ public virtual void SetSystemModule(ModuleDesc systemModule) // Initialize all well known types - it will save us from checking the name for each loaded type for (int typeIndex = 0; typeIndex < _wellKnownTypes.Length; typeIndex++) { - // Require System.Object to be present as a minimal sanity check. + // Require System.Object to be present as a minimal sanity check. // The set of required well-known types is not strictly defined since different .NET profiles implement different subsets. MetadataType type = systemModule.GetType("System", s_wellKnownTypeNames[typeIndex], throwIfNotFound: typeIndex == (int)WellKnownType.Object); if (type != null) @@ -88,7 +87,7 @@ public override DefType GetWellKnownType(WellKnownType wellKnownType, bool throw int typeIndex = (int)wellKnownType - 1; DefType type = _wellKnownTypes[typeIndex]; - if (type == null && throwIfNotFound) + if (type == null && throwIfNotFound) ThrowHelper.ThrowTypeLoadException("System", s_wellKnownTypeNames[typeIndex], SystemModule); return type; diff --git a/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs b/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs index 51cf7291cdd74..a5a5e5ab7d3bd 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/TypeDesc.cs @@ -117,7 +117,6 @@ internal void SetWellKnownType(WellKnownType wellKnownType) case WellKnownType.RuntimeMethodHandle: case WellKnownType.RuntimeFieldHandle: case WellKnownType.TypedReference: - case WellKnownType.ByReferenceOfT: flags = TypeFlags.ValueType; break; @@ -298,18 +297,6 @@ public bool IsNullable } } - /// - /// Gets a value indicating whether this is a generic definition, or - /// an instance of System.ByReference`1. - /// - public bool IsByReferenceOfT - { - get - { - return this.GetTypeDefinition().IsWellKnownType(WellKnownType.ByReferenceOfT); - } - } - /// /// Gets a value indicating whether this is an array type (). /// Note this will return true for both multidimensional array types and vector types. diff --git a/src/coreclr/tools/Common/TypeSystem/Common/WellKnownType.cs b/src/coreclr/tools/Common/TypeSystem/Common/WellKnownType.cs index cc3e5636058f7..b16257f21697e 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/WellKnownType.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/WellKnownType.cs @@ -46,6 +46,5 @@ public enum WellKnownType Exception, TypedReference, - ByReferenceOfT, } } diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs index 4c11c0570637d..01b82b84027f8 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/IL/MarshalHelpers.cs @@ -411,7 +411,6 @@ internal static MarshallerKind GetMarshallerKind( bool isBlittable = MarshalUtils.IsBlittableType(type); // Blittable generics are allowed to be marshalled with the following exceptions: - // * ByReference: This represents an interior pointer and is not actually blittable // * Nullable: We don't want to be locked into the default behavior as we may want special handling later // * Vector64: Represents the __m64 ABI primitive which requires currently unimplemented handling // * Vector128: Represents the __m128 ABI primitive which requires currently unimplemented handling @@ -420,7 +419,6 @@ internal static MarshallerKind GetMarshallerKind( // We can't block these types for field scenarios for back-compat reasons. if (type.HasInstantiation && !isField && (!isBlittable - || InteropTypes.IsSystemByReference(context, type) || InteropTypes.IsSystemSpan(context, type) || InteropTypes.IsSystemReadOnlySpan(context, type) || InteropTypes.IsSystemNullable(context, type) diff --git a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs index ac32fbbe54647..29c03c6e54dea 100644 --- a/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs +++ b/src/coreclr/tools/Common/TypeSystem/Interop/InteropTypes.cs @@ -122,11 +122,6 @@ public static bool IsSystemArgIterator(TypeSystemContext context, TypeDesc type) return IsCoreNamedType(context, type, "System", "ArgIterator"); } - public static bool IsSystemByReference(TypeSystemContext context, TypeDesc type) - { - return IsCoreNamedType(context, type, "System", "ByReference`1"); - } - public static bool IsSystemSpan(TypeSystemContext context, TypeDesc type) { return IsCoreNamedType(context, type, "System", "Span`1"); diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs index bc4de930eb8d2..6c8a0df4c1784 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/IL/ILImporter.Scanner.cs @@ -370,11 +370,6 @@ private void ImportCall(ILOpcode opcode, int token) return; } - if (method.OwningType.IsByReferenceOfT && (method.IsConstructor || method.Name == "get_Value")) - { - return; - } - if (IsEETypePtrOf(method)) { if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs index ad294d7227d46..3963a30ea7b1f 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/DependencyAnalysis/ReadyToRun/GCRefMapBuilder.cs @@ -7,15 +7,15 @@ using Internal.TypeSystem; -// The GCRef map is used to encode GC type of arguments for callsites. Logically, it is sequence where pos is +// The GCRef map is used to encode GC type of arguments for callsites. Logically, it is sequence where pos is // position of the reference in the stack frame and token is type of GC reference (one of GCREFMAP_XXX values). // -// - The encoding always starts at the byte boundary. The high order bit of each byte is used to signal end of the encoding +// - The encoding always starts at the byte boundary. The high order bit of each byte is used to signal end of the encoding // stream. The last byte has the high order bit zero. It means that there are 7 useful bits in each byte. // - "pos" is always encoded as delta from previous pos. -// - The basic encoding unit is two bits. Values 0, 1 and 2 are the common constructs (skip single slot, GC reference, interior -// pointer). Value 3 means that extended encoding follows. -// - The extended information is integer encoded in one or more four bit blocks. The high order bit of the four bit block is +// - The basic encoding unit is two bits. Values 0, 1 and 2 are the common constructs (skip single slot, GC reference, interior +// pointer). Value 3 means that extended encoding follows. +// - The extended information is integer encoded in one or more four bit blocks. The high order bit of the four bit block is // used to signal the end. // - For x86, the encoding starts by size of the callee poped stack. The size is encoded using the same mechanism as above (two bit // basic encoding, with extended encoding for large values). @@ -35,7 +35,7 @@ public class GCRefMapBuilder private int _pendingByte; /// - /// Number of bits in pending byte. Note that the trailing zero bits are not written out, + /// Number of bits in pending byte. Note that the trailing zero bits are not written out, /// so this can be more than 7. /// private int _bits; @@ -293,7 +293,7 @@ private void GcScanValueType(TypeDesc type, ArgDestination argDest, int delta, C private void FindByRefPointerOffsetsInByRefLikeObject(TypeDesc type, ArgDestination argDest, int delta, CORCOMPILE_GCREFMAP_TOKENS[] frame) { - if (type.IsByReferenceOfT || type.IsByRef) + if (type.IsByRef) { argDest.GcMark(frame, delta, interior: true); return; diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs index f507cabb4d3e3..62725929b8100 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunMetadataFieldLayoutAlgorithm.cs @@ -253,7 +253,7 @@ private void GetElementTypeInfoGeneric( size = fieldType.GetElementSize().AsInt; alignment = size; } - else if (fieldType.IsByRef || fieldType.IsByRefLike || fieldType.IsByReferenceOfT) + else if (fieldType.IsByRef || fieldType.IsByRefLike) { ThrowHelper.ThrowTypeLoadException(ExceptionStringID.ClassLoadGeneral, fieldDesc.OwningType); } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/InstanceFieldLayout.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/InstanceFieldLayout.cs index 656d075135228..b49dd4ff72930 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/InstanceFieldLayout.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/InstanceFieldLayout.cs @@ -296,7 +296,7 @@ namespace IsByRefLike { public ref struct ByRefLikeStruct { - ByReference ByRef; + ref object ByRef; } public struct NotByRefLike diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Platform.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Platform.cs index ac8b380d19416..886f7aa791fd6 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Platform.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/CoreTestAssembly/Platform.cs @@ -48,7 +48,7 @@ public struct Double { } public abstract class ValueType { } public abstract class Enum : ValueType { } public struct Nullable where T : struct { } - + public sealed class String { } public abstract class Array : System.Collections.IList { } public abstract class Delegate { } @@ -68,11 +68,9 @@ public class Exception { } public ref struct TypedReference { - private readonly ByReference _value; + private readonly ref byte _value; private readonly RuntimeTypeHandle _typeHandle; } - - public ref struct ByReference { } } namespace System.Collections diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/InstanceFieldLayout.il b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/InstanceFieldLayout.il index 83906647e842c..35bf1dd165fff 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/InstanceFieldLayout.il +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/ILTestAssembly/InstanceFieldLayout.il @@ -4,18 +4,18 @@ .class public sequential ansi sealed beforefieldinit IsByRefLike.InvalidStruct extends [CoreTestAssembly]System.ValueType { - .field private valuetype [CoreTestAssembly]System.ByReference`1 ByRef + .field private object& ByRef } .class public auto ansi beforefieldinit IsByRefLike.InvalidClass1 extends [CoreTestAssembly]System.Object { - .field private valuetype [CoreTestAssembly]System.ByReference`1 ByRef + .field private object& ByRef } .class public auto ansi beforefieldinit IsByRefLike.InvalidClass2 extends [CoreTestAssembly]System.Object { - .custom instance void [CoreTestAssembly]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( 01 00 00 00 ) - .field private valuetype [CoreTestAssembly]System.ByReference`1 ByRef + .custom instance void [CoreTestAssembly]System.Runtime.CompilerServices.IsByRefLikeAttribute::.ctor() = ( 01 00 00 00 ) + .field private object& ByRef } diff --git a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/InstanceFieldLayoutTests.cs b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/InstanceFieldLayoutTests.cs index e92749b5ab272..0a60a72a4a640 100644 --- a/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/InstanceFieldLayoutTests.cs +++ b/src/coreclr/tools/aot/ILCompiler.TypeSystem.Tests/InstanceFieldLayoutTests.cs @@ -31,7 +31,7 @@ public void TestExplicitLayout() MetadataType t = _testModule.GetType("Explicit", "Class1"); // With 64bit, there should be 8 bytes for the System.Object EE data pointer + - // 10 bytes up until the offset of the char field + the char size of 2 + we + // 10 bytes up until the offset of the char field + the char size of 2 + we // round up the whole instance size to the next pointer size (+4) = 24 Assert.Equal(24, t.InstanceByteCount.AsInt); @@ -95,7 +95,7 @@ public void TestExplicitTypeLayoutWithInheritance() if (f.Name == "Lol") { - // First field after base class, with offset 0 so it should lie on the byte count of + // First field after base class, with offset 0 so it should lie on the byte count of // the base class = 20 Assert.Equal(20, f.Offset.AsInt); } @@ -821,11 +821,6 @@ public void TestByRefLikeTypes() Assert.True(type.IsByRefLike); } - { - DefType type = _context.GetWellKnownType(WellKnownType.ByReferenceOfT); - Assert.True(type.IsByRefLike); - } - { DefType type = _testModule.GetType("IsByRefLike", "ByRefLikeStruct"); Assert.True(type.IsByRefLike); diff --git a/src/coreclr/tools/dotnet-pgo/dotnet-pgo.csproj b/src/coreclr/tools/dotnet-pgo/dotnet-pgo.csproj index 14a99e98aad28..ab5cc92e42435 100644 --- a/src/coreclr/tools/dotnet-pgo/dotnet-pgo.csproj +++ b/src/coreclr/tools/dotnet-pgo/dotnet-pgo.csproj @@ -21,6 +21,9 @@ $(Description) Microsoft.Diagnostics.Tools.Pgo Major + + 10 From d7adc38be3cf47387dc3e34f95656bfa63bcc5e5 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 18 May 2022 15:28:37 -0700 Subject: [PATCH 06/22] Remove ByReference from mono/ --- .../src/System/TypedReference.Mono.cs | 2 +- src/mono/mono/metadata/class-init.c | 25 +------------------ src/mono/mono/mini/interp/transform.c | 15 ----------- src/mono/mono/mini/intrinsics.c | 21 ---------------- 4 files changed, 2 insertions(+), 61 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/TypedReference.Mono.cs b/src/mono/System.Private.CoreLib/src/System/TypedReference.Mono.cs index 5dffd483d6bd1..27364dacc7afb 100644 --- a/src/mono/System.Private.CoreLib/src/System/TypedReference.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/TypedReference.Mono.cs @@ -11,7 +11,7 @@ public ref partial struct TypedReference #region sync with object-internals.h #pragma warning disable CA1823 // used by runtime private readonly RuntimeTypeHandle type; - private readonly ByReference _value; + private readonly ref byte _value; private readonly IntPtr _type; #pragma warning restore CA1823 #endregion diff --git a/src/mono/mono/metadata/class-init.c b/src/mono/mono/metadata/class-init.c index d22bab650ed0b..f61870a72fd79 100644 --- a/src/mono/mono/metadata/class-init.c +++ b/src/mono/mono/metadata/class-init.c @@ -1835,35 +1835,12 @@ class_has_ref_fields (MonoClass *klass) return klass->has_ref_fields; } -static gboolean -class_is_byreference (MonoClass* klass) -{ - const char* klass_name_space = m_class_get_name_space (klass); - const char* klass_name = m_class_get_name (klass); - MonoImage* klass_image = m_class_get_image (klass); - gboolean in_corlib = klass_image == mono_defaults.corlib; - - if (in_corlib && - !strcmp (klass_name_space, "System") && - !strcmp (klass_name, "ByReference`1")) { - return TRUE; - } - - return FALSE; -} - static gboolean type_has_ref_fields (MonoType *ftype) { if (m_type_is_byref (ftype) || (MONO_TYPE_ISSTRUCT (ftype) && class_has_ref_fields (mono_class_from_mono_type_internal (ftype)))) return TRUE; - /* Check for the ByReference`1 type */ - if (MONO_TYPE_ISSTRUCT (ftype)) { - MonoClass* klass = mono_class_from_mono_type_internal (ftype); - return class_is_byreference (klass); - } - return FALSE; } @@ -1982,7 +1959,7 @@ validate_struct_fields_overlaps (guint8 *layout_check, int layout_size, MonoClas } else { int align = 0; int size = mono_type_size (field->type, &align); - guint8 type = type_has_references (klass, ftype) ? 1 : (m_type_is_byref (ftype) || class_is_byreference (klass)) ? 2 : 3; + guint8 type = type_has_references (klass, ftype) ? 1 : m_type_is_byref (ftype) ? 2 : 3; // Mark the bytes used by this fields type based on if it contains references or not. // Make sure there are no overlaps between object and non-object fields. diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index d1766217cf6ab..2d2af7444fdd2 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -1857,9 +1857,6 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas !strcmp (klass_name, "SpanHelpers") && !strcmp (tm, "ClearWithReferences")) { *op = MINT_INTRINS_CLEAR_WITH_REFERENCES; - } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "ByReference`1")) { - g_assert (!strcmp (tm, "get_Value")); - *op = MINT_LDIND_I; } else if (in_corlib && !strcmp (klass_name_space, "System") && !strcmp (klass_name, "Marvin")) { if (!strcmp (tm, "Block")) { InterpInst *ldloca2 = td->last_ins; @@ -5532,18 +5529,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG); td->last_ins->flags |= INTERP_INST_FLAG_CALL; td->last_ins->info.call_args = call_args; - } else if (m_class_get_image (klass) == mono_defaults.corlib && - !strcmp (m_class_get_name (m->klass), "ByReference`1") && - !strcmp (m->name, ".ctor")) { - /* public ByReference(ref T value) */ - MONO_PROFILER_RAISE (inline_method, (td->rtm->method, m)); - g_assert (csignature->hasthis && csignature->param_count == 1); - td->sp--; - /* We already have the vt on top of the stack. Just do a dummy mov that should be optimized out */ - interp_add_ins (td, MINT_MOV_P); - interp_ins_set_sreg (td->last_ins, td->sp [0].local); - push_type_vt (td, klass, mono_class_value_size (klass, NULL)); - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else if (m_class_get_image (klass) == mono_defaults.corlib && (!strcmp (m_class_get_name (m->klass), "Span`1") || !strcmp (m_class_get_name (m->klass), "ReadOnlySpan`1")) && diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 25d89f2ddcfe4..9df635092ed7b 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -75,21 +75,9 @@ mono_type_is_native_blittable (MonoType *t) MonoInst* mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { - const char* cmethod_klass_name_space = m_class_get_name_space (cmethod->klass); - const char* cmethod_klass_name = m_class_get_name (cmethod->klass); - MonoImage *cmethod_klass_image = m_class_get_image (cmethod->klass); - gboolean in_corlib = cmethod_klass_image == mono_defaults.corlib; MonoInst *ins = NULL; /* Required intrinsics are always used even with -O=-intrins */ - if (in_corlib && - !strcmp (cmethod_klass_name_space, "System") && - !strcmp (cmethod_klass_name, "ByReference`1")) { - /* public ByReference(ref T value) */ - g_assert (fsig->hasthis && fsig->param_count == 1); - EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [0]->dreg, 0, args [1]->dreg); - return ins; - } if (!(cfg->opt & MONO_OPT_INTRINS)) return NULL; @@ -806,15 +794,6 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign gboolean in_corlib = cmethod_klass_image == mono_defaults.corlib; /* Required intrinsics are always used even with -O=-intrins */ - if (in_corlib && - !strcmp (cmethod_klass_name_space, "System") && - !strcmp (cmethod_klass_name, "ByReference`1") && - !strcmp (cmethod->name, "get_Value")) { - g_assert (fsig->hasthis && fsig->param_count == 0); - int dreg = alloc_preg (cfg); - EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, dreg, args [0]->dreg, 0); - return ins; - } if (!(cfg->opt & MONO_OPT_INTRINS)) return NULL; From 9bb79ef6cf1b0df9964ca9bf22ae737c09eb1245 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Thu, 19 May 2022 13:48:20 -0700 Subject: [PATCH 07/22] Limit net6.0 TFM in DiagnosticsSource to C# 10. --- .../src/System.Diagnostics.DiagnosticSource.csproj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj index fabda09091ab6..b8f3b225c7207 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj @@ -6,6 +6,8 @@ $(NoWarn);SA1205;CA1845 false true + + 10 Provides Classes that allow you to decouple code logging rich (unserializable) diagnostics/telemetry (e.g. framework) from code that consumes it (e.g. tools) Commonly Used Types: From b4042b902bd2cb5088a0421f9142673ce48bf9a1 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 24 Jun 2022 07:50:26 -0700 Subject: [PATCH 08/22] Apply more fixes --- .../src/System/TypedReference.CoreCLR.cs | 4 ++-- .../src/System/Globalization/DateTimeFormat.cs | 4 ++-- .../src/System/Globalization/TimeSpanFormat.cs | 2 +- .../src/System/Reflection/InvokerEmitUtil.cs | 10 +++++----- .../src/System/TypedReference.cs | 2 +- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs index 21009eedef292..dc7e3ee58693f 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/TypedReference.CoreCLR.cs @@ -38,11 +38,11 @@ public ref partial struct TypedReference if (pMethodTable->IsValueType) { - result = RuntimeHelpers.Box(pMethodTable, ref value._value.Value); + result = RuntimeHelpers.Box(pMethodTable, ref value._value); } else { - result = Unsafe.As(ref value._value.Value); + result = Unsafe.As(ref value._value); } return result; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs index cfdbe719b8d79..bb5917a06fd13 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/DateTimeFormat.cs @@ -299,7 +299,7 @@ private static string FormatHebrewMonthName(DateTime time, int month, int repeat // The pos should point to a quote character. This method will // append to the result StringBuilder the string enclosed by the quote character. // - internal static int ParseQuoteString(ReadOnlySpan format, int pos, ref ValueStringBuilder result) + internal static int ParseQuoteString(scoped ReadOnlySpan format, int pos, ref ValueStringBuilder result) { // // NOTE : pos will be the index of the quote character in the 'format' string. @@ -444,7 +444,7 @@ private static bool IsUseGenitiveForm(ReadOnlySpan format, int index, int // Actions: Format the DateTime instance using the specified format. // private static void FormatCustomized( - DateTime dateTime, ReadOnlySpan format, DateTimeFormatInfo dtfi, TimeSpan offset, ref ValueStringBuilder result) + DateTime dateTime, scoped ReadOnlySpan format, DateTimeFormatInfo dtfi, TimeSpan offset, ref ValueStringBuilder result) { Calendar cal = dtfi.Calendar; diff --git a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs index 8695e9b9beac1..f66e5482c36d9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Globalization/TimeSpanFormat.cs @@ -300,7 +300,7 @@ private static void WriteDigits(uint value, Span buffer) } /// Format the TimeSpan instance using the specified format. - private static void FormatCustomized(TimeSpan value, ReadOnlySpan format, DateTimeFormatInfo dtfi, ref ValueStringBuilder result) + private static void FormatCustomized(TimeSpan value, scoped ReadOnlySpan format, DateTimeFormatInfo dtfi, ref ValueStringBuilder result) { Debug.Assert(dtfi != null); diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs index f13850b1dcc9b..e3c585d21ef81 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs @@ -55,7 +55,7 @@ public static unsafe InvokeFunc CreateInvokeDelegate(MethodBase method) il.Emit(OpCodes.Add); } - il.Emit(OpCodes.Call, Methods.ByReferenceOfByte_Value()); // This can be replaced by ldfld once byref fields are available in C# + il.Emit(OpCodes.Ldfld, Methods.ByReferenceOfByte_Value()); RuntimeType parameterType = (RuntimeType)parameters[i].ParameterType; if (!parameterType.IsByRef) @@ -166,10 +166,10 @@ public static void Throw_NullReference_InvokeNullRefReturned() private static class Methods { - private static MethodInfo? s_ByReferenceOfByte_Value; - [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(ByReference<>))] - public static MethodInfo ByReferenceOfByte_Value() => - s_ByReferenceOfByte_Value ??= typeof(ByReference).GetMethod("get_Value")!; + private static FieldInfo? s_ByReferenceOfByte_Value; + [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(ByReference))] + public static FieldInfo ByReferenceOfByte_Value() => + s_ByReferenceOfByte_Value ??= typeof(ByReference).GetField("Value")!; private static MethodInfo? s_ThrowHelper_Throw_NullReference_InvokeNullRefReturned; [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(ThrowHelper))] diff --git a/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs b/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs index dd13bfd894a02..2ff8dc78b9c86 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TypedReference.cs @@ -75,7 +75,7 @@ public override bool Equals(object? o) throw new NotSupportedException(SR.NotSupported_NYI); } - internal bool IsNull => Unsafe.IsNullRef(ref _value.Value) && _type == IntPtr.Zero; + internal bool IsNull => Unsafe.IsNullRef(ref _value) && _type == IntPtr.Zero; public static Type GetTargetType(TypedReference value) { From a87752f635d0ded68a99aa7b1c45aa21d2997cda Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 24 Jun 2022 15:49:27 -0700 Subject: [PATCH 09/22] Remove unnecessary scoped on GetReference API. --- src/libraries/System.Memory/ref/System.Memory.cs | 4 ++-- .../src/System/Runtime/InteropServices/MemoryMarshal.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Memory/ref/System.Memory.cs b/src/libraries/System.Memory/ref/System.Memory.cs index 2ca725c301550..e70356c5975a7 100644 --- a/src/libraries/System.Memory/ref/System.Memory.cs +++ b/src/libraries/System.Memory/ref/System.Memory.cs @@ -550,8 +550,8 @@ public static partial class MemoryMarshal public static System.Span CreateSpan(scoped ref T reference, int length) { throw null; } public static ref T GetArrayDataReference(T[] array) { throw null; } public static ref byte GetArrayDataReference(System.Array array) { throw null; } - public static ref T GetReference(scoped System.ReadOnlySpan span) { throw null; } - public static ref T GetReference(scoped System.Span span) { throw null; } + public static ref T GetReference(System.ReadOnlySpan span) { throw null; } + public static ref T GetReference(System.Span span) { throw null; } public static T Read(System.ReadOnlySpan source) where T : struct { throw null; } public static System.Collections.Generic.IEnumerable ToEnumerable(System.ReadOnlyMemory memory) { throw null; } public static bool TryGetArray(System.ReadOnlyMemory memory, out System.ArraySegment segment) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index c69425bc3a82c..a60ab47e6b2ee 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -77,13 +77,13 @@ public static Memory AsMemory(ReadOnlyMemory memory) => /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(scoped Span span) => ref Unsafe.AsRef(in span._reference); + public static ref T GetReference(Span span) => ref Unsafe.AsRef(in span._reference); /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(scoped ReadOnlySpan span) => ref Unsafe.AsRef(in span._reference); + public static ref T GetReference(ReadOnlySpan span) => ref Unsafe.AsRef(in span._reference); /// /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used From a30d754ecdba5269281e6ae69cd656fe63af36ee Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Wed, 29 Jun 2022 18:55:52 -0700 Subject: [PATCH 10/22] Remove temporary LifetimeAnnotationAttribute This is supplied by Roslyn. --- .../System.Private.CoreLib.Shared.projitems | 1 - .../LifetimeAnnotationAttribute.cs | 25 ------------------- .../System.Runtime/ref/System.Runtime.cs | 8 ------ 3 files changed, 34 deletions(-) delete mode 100644 src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 93eab8cdde985..a079ceb5f11ab 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -758,7 +758,6 @@ - diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs deleted file mode 100644 index f792a7a8e2248..0000000000000 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/CompilerServices/LifetimeAnnotationAttribute.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System; - -namespace System.Runtime.CompilerServices -{ - /// - /// This type is defined until we consume the C# 11 compiler. - /// - /// - /// Also remove in the reference assemblies. - /// - [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] - internal sealed class LifetimeAnnotationAttribute : Attribute - { - public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) - { - IsRefScoped = isRefScoped; - IsValueScoped = isValueScoped; - } - public bool IsRefScoped { get; } - public bool IsValueScoped { get; } - } -} diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index dde78feb2ace1..a3070e881913b 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -12540,14 +12540,6 @@ public partial interface ITuple object? this[int index] { get; } int Length { get; } } - // See src\libraries\System.Private.CoreLib\src\System\Runtime\CompilerServices\LifetimeAnnotationAttribute.cs - [System.AttributeUsageAttribute(System.AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] - internal sealed class LifetimeAnnotationAttribute : System.Attribute - { - public LifetimeAnnotationAttribute(bool isRefScoped, bool isValueScoped) { throw null; } - public bool IsRefScoped { get { throw null; } } - public bool IsValueScoped { get { throw null; } } - } public enum LoadHint { Default = 0, From 73a85a53d28422baa47fa566c9e4dfbdd9f72af4 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Thu, 30 Jun 2022 10:13:11 -0700 Subject: [PATCH 11/22] Update to Roslyn compiler with ref field support. --- eng/Versions.props | 2 +- .../src/System/TimeZoneInfo.Unix.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eng/Versions.props b/eng/Versions.props index b1d2cf6d02147..924b6da3adf67 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -49,7 +49,7 @@ - 4.4.0-1.22315.13 + 4.4.0-1.22328.22 2.0.0-preview.4.22252.4 diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs index 99aec155a2942..3e164bc80ff17 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.cs @@ -1007,7 +1007,7 @@ private static bool TZif_ParsePosixFormat( return !standardName.IsEmpty && !standardOffset.IsEmpty; } - private static ReadOnlySpan TZif_ParsePosixName(ReadOnlySpan posixFormat, ref int index) + private static ReadOnlySpan TZif_ParsePosixName(ReadOnlySpan posixFormat, scoped ref int index) { bool isBracketEnclosed = index < posixFormat.Length && posixFormat[index] == '<'; if (isBracketEnclosed) @@ -1034,10 +1034,10 @@ private static ReadOnlySpan TZif_ParsePosixName(ReadOnlySpan posixFo } } - private static ReadOnlySpan TZif_ParsePosixOffset(ReadOnlySpan posixFormat, ref int index) => + private static ReadOnlySpan TZif_ParsePosixOffset(ReadOnlySpan posixFormat, scoped ref int index) => TZif_ParsePosixString(posixFormat, ref index, c => !char.IsDigit(c) && c != '+' && c != '-' && c != ':'); - private static void TZif_ParsePosixDateTime(ReadOnlySpan posixFormat, ref int index, out ReadOnlySpan date, out ReadOnlySpan time) + private static void TZif_ParsePosixDateTime(ReadOnlySpan posixFormat, scoped ref int index, out ReadOnlySpan date, out ReadOnlySpan time) { time = null; @@ -1049,13 +1049,13 @@ private static void TZif_ParsePosixDateTime(ReadOnlySpan posixFormat, ref } } - private static ReadOnlySpan TZif_ParsePosixDate(ReadOnlySpan posixFormat, ref int index) => + private static ReadOnlySpan TZif_ParsePosixDate(ReadOnlySpan posixFormat, scoped ref int index) => TZif_ParsePosixString(posixFormat, ref index, c => c == '/' || c == ','); - private static ReadOnlySpan TZif_ParsePosixTime(ReadOnlySpan posixFormat, ref int index) => + private static ReadOnlySpan TZif_ParsePosixTime(ReadOnlySpan posixFormat, scoped ref int index) => TZif_ParsePosixString(posixFormat, ref index, c => c == ','); - private static ReadOnlySpan TZif_ParsePosixString(ReadOnlySpan posixFormat, ref int index, Func breakCondition) + private static ReadOnlySpan TZif_ParsePosixString(ReadOnlySpan posixFormat, scoped ref int index, Func breakCondition) { int startIndex = index; for (; index < posixFormat.Length; index++) From c496c66b2efe144ad82575493e43625b0d70e384 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Thu, 30 Jun 2022 10:41:40 -0700 Subject: [PATCH 12/22] Update for compiler warning/error. --- src/mono/mono/mini/intrinsics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index bb8dac9d0f982..53ccc077c0783 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -80,7 +80,7 @@ mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat /* Required intrinsics are always used even with -O=-intrins */ if (!(cfg->opt & MONO_OPT_INTRINS)) - return NULL; + return ins; #ifdef MONO_ARCH_SIMD_INTRINSICS if (cfg->opt & MONO_OPT_SIMD) { @@ -90,7 +90,7 @@ mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat } #endif - return NULL; + return ins; } static MonoInst* From b0744365217f4b22d661a7995b069ee57b7957b3 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Thu, 30 Jun 2022 14:31:44 -0700 Subject: [PATCH 13/22] Review feedback. --- .../src/System/Reflection/InvokerEmitUtil.cs | 1 - .../src/System/Runtime/InteropServices/MemoryMarshal.cs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs index 97bad41593d9e..4e4bab9aa36fc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/InvokerEmitUtil.cs @@ -167,7 +167,6 @@ public static void Throw_NullReference_InvokeNullRefReturned() private static class Methods { private static FieldInfo? s_ByReferenceOfByte_Value; - [DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(ByReference))] public static FieldInfo ByReferenceOfByte_Value() => s_ByReferenceOfByte_Value ??= typeof(ByReference).GetField("Value")!; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index a60ab47e6b2ee..50f34c4610ac5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -90,14 +90,14 @@ public static Memory AsMemory(ReadOnlyMemory memory) => /// for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static unsafe ref T GetNonNullPinnableReference(scoped Span span) => ref (span.Length != 0) ? ref Unsafe.AsRef(in span._reference) : ref Unsafe.AsRef((void*)1); + internal static unsafe ref T GetNonNullPinnableReference(Span span) => ref (span.Length != 0) ? ref Unsafe.AsRef(in span._reference) : ref Unsafe.AsRef((void*)1); /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to fake non-null pointer. Such a reference /// can be used for pinning but must never be dereferenced. This is useful for interop with methods that do not accept null pointers for zero-sized buffers. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static unsafe ref T GetNonNullPinnableReference(scoped ReadOnlySpan span) => ref (span.Length != 0) ? ref Unsafe.AsRef(in span._reference) : ref Unsafe.AsRef((void*)1); + internal static unsafe ref T GetNonNullPinnableReference(ReadOnlySpan span) => ref (span.Length != 0) ? ref Unsafe.AsRef(in span._reference) : ref Unsafe.AsRef((void*)1); /// /// Casts a Span of one primitive type to another primitive type . From bafd6cf1270942da10a50d63ede7940635ecd85b Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Thu, 30 Jun 2022 17:05:17 -0700 Subject: [PATCH 14/22] Treat a byref as a native pointer. --- src/mono/mono/metadata/marshal-shared.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mono/mono/metadata/marshal-shared.c b/src/mono/mono/metadata/marshal-shared.c index 9479611e9d57b..74f3672148f31 100644 --- a/src/mono/mono/metadata/marshal-shared.c +++ b/src/mono/mono/metadata/marshal-shared.c @@ -830,9 +830,7 @@ mono_marshal_shared_emit_struct_conv_full (MonoMethodBuilder *mb, MonoClass *kla case MONO_MARSHAL_CONV_NONE: { int t; - //XXX a byref field!?!? that's not allowed! and worse, it might miss a WB - g_assert (!m_type_is_byref (ftype)); - if (ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) { + if (m_type_is_byref (ftype) || ftype->type == MONO_TYPE_I || ftype->type == MONO_TYPE_U) { mono_mb_emit_ldloc (mb, 1); mono_mb_emit_ldloc (mb, 0); mono_mb_emit_byte (mb, CEE_LDIND_I); From e785b70e823250fa4f2734d27a458e6a5d0c356d Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 1 Jul 2022 13:39:44 -0700 Subject: [PATCH 15/22] Remove unnecessary Unsafe.AsRef usage. --- .../src/System/Runtime/InteropServices/MemoryMarshal.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index 50f34c4610ac5..4e3eadfa842b9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -77,13 +77,13 @@ public static Memory AsMemory(ReadOnlyMemory memory) => /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(Span span) => ref Unsafe.AsRef(in span._reference); + public static ref T GetReference(Span span) => ref span._reference; /// /// Returns a reference to the 0th element of the ReadOnlySpan. If the ReadOnlySpan is empty, returns a reference to the location where the 0th element /// would have been stored. Such a reference may or may not be null. It can be used for pinning but must never be dereferenced. /// - public static ref T GetReference(ReadOnlySpan span) => ref Unsafe.AsRef(in span._reference); + public static ref T GetReference(ReadOnlySpan span) => ref span._reference; /// /// Returns a reference to the 0th element of the Span. If the Span is empty, returns a reference to fake non-null pointer. Such a reference can be used From 51089af78b6f9f26a97b040f8b3b46c4626b5744 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 1 Jul 2022 13:40:01 -0700 Subject: [PATCH 16/22] Remove missed mention of ByReference. --- .../tests/FormatterServicesTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime.Serialization.Formatters/tests/FormatterServicesTests.cs b/src/libraries/System.Runtime.Serialization.Formatters/tests/FormatterServicesTests.cs index 0a04f250a3f8a..b1ae8a2294e9e 100644 --- a/src/libraries/System.Runtime.Serialization.Formatters/tests/FormatterServicesTests.cs +++ b/src/libraries/System.Runtime.Serialization.Formatters/tests/FormatterServicesTests.cs @@ -133,7 +133,7 @@ private ref struct StructWithSpanField [Theory] [MemberData(nameof(GetUninitializedObject_ByRefLikeType_NetCore_TestData))] - [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, "Some runtimes don't support or recognise Span, ReadOnlySpan or ByReference as ref types.")] + [SkipOnTargetFramework(~TargetFrameworkMonikers.Netcoreapp, "Some runtimes don't support or recognise Span or ReadOnlySpan as ref types.")] public void GetUninitializedObject_ByRefLikeType_NetCore_ThrowsNotSupportedException(Type type) { Assert.Throws(() => FormatterServices.GetUninitializedObject(type)); From 82eb3cea1b093260cbe3f3247700d598e4f7794f Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 1 Jul 2022 13:47:52 -0700 Subject: [PATCH 17/22] Update comments with those approved in official docs. --- .../System/Runtime/InteropServices/MemoryMarshal.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs index 4e3eadfa842b9..c91aa21b5e7d0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs @@ -217,7 +217,11 @@ ref Unsafe.As(ref MemoryMarshal.GetReference(span)), /// A reference to data. /// The number of elements the memory contains. /// A span representing the specified reference and length. - /// The lifetime of the returned span will not be validated for safety by span-aware languages. + /// + /// This method should be used with caution. It is dangerous because the length argument is not checked. + /// Even though the ref is annotated as scoped, it will be stored into the returned span, and the lifetime + /// of the returned span will not be validated for safety, even by span-aware languages. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Span CreateSpan(scoped ref T reference, int length) => new Span(ref Unsafe.AsRef(in reference), length); @@ -230,7 +234,11 @@ public static Span CreateSpan(scoped ref T reference, int length) => /// A reference to data. /// The number of elements the memory contains. /// A read-only span representing the specified reference and length. - /// The lifetime of the returned span will not be validated for safety by span-aware languages. + /// + /// This method should be used with caution. It is dangerous because the length argument is not checked. + /// Even though the ref is annotated as scoped, it will be stored into the returned span, and the lifetime + /// of the returned span will not be validated for safety, even by span-aware languages. + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ReadOnlySpan CreateReadOnlySpan(scoped ref T reference, int length) => new ReadOnlySpan(ref Unsafe.AsRef(in reference), length); From fa5ea6c1c2684fc6179b8e84b9a7061402db852a Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 1 Jul 2022 14:12:52 -0700 Subject: [PATCH 18/22] Bring back recognition of the ByReference type in the mono interpreter. --- src/mono/mono/mini/interp/transform.c | 12 ++++++++++++ src/mono/mono/mini/intrinsics.c | 16 ++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 7014a61a84c25..ad01730ba9a32 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -5548,6 +5548,18 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG); td->last_ins->flags |= INTERP_INST_FLAG_CALL; td->last_ins->info.call_args = call_args; + } else if (m_class_get_image (klass) == mono_defaults.corlib && + !strcmp (m_class_get_name (m->klass), "ByReference") && + !strcmp (m->name, ".ctor")) { + /* public ByReference(ref T value) */ + MONO_PROFILER_RAISE (inline_method, (td->rtm->method, m)); + g_assert (csignature->hasthis && csignature->param_count == 1); + td->sp--; + /* We already have the vt on top of the stack. Just do a dummy mov that should be optimized out */ + interp_add_ins (td, MINT_MOV_P); + interp_ins_set_sreg (td->last_ins, td->sp [0].local); + push_type_vt (td, klass, mono_class_value_size (klass, NULL)); + interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else if (m_class_get_image (klass) == mono_defaults.corlib && (!strcmp (m_class_get_name (m->klass), "Span`1") || !strcmp (m_class_get_name (m->klass), "ReadOnlySpan`1")) && diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 53ccc077c0783..e4e72be079ecf 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -75,12 +75,24 @@ mono_type_is_native_blittable (MonoType *t) MonoInst* mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { + const char* cmethod_klass_name_space = m_class_get_name_space (cmethod->klass); + const char* cmethod_klass_name = m_class_get_name (cmethod->klass); + MonoImage *cmethod_klass_image = m_class_get_image (cmethod->klass); + gboolean in_corlib = cmethod_klass_image == mono_defaults.corlib; MonoInst *ins = NULL; /* Required intrinsics are always used even with -O=-intrins */ + if (in_corlib && + !strcmp (cmethod_klass_name_space, "System") && + !strcmp (cmethod_klass_name, "ByReference")) { + /* public ByReference(ref T value) */ + g_assert (fsig->hasthis && fsig->param_count == 1); + EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [0]->dreg, 0, args [1]->dreg); + return ins; + } if (!(cfg->opt & MONO_OPT_INTRINS)) - return ins; + return NULL; #ifdef MONO_ARCH_SIMD_INTRINSICS if (cfg->opt & MONO_OPT_SIMD) { @@ -90,7 +102,7 @@ mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat } #endif - return ins; + return NULL; } static MonoInst* From 3180604802b0e7ddc7702f0350a03108ff4247f0 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 1 Jul 2022 20:09:05 -0700 Subject: [PATCH 19/22] Revert "Bring back recognition of the ByReference type" This reverts commit fa5ea6c1c2684fc6179b8e84b9a7061402db852a. --- src/mono/mono/mini/interp/transform.c | 12 ------------ src/mono/mono/mini/intrinsics.c | 16 ++-------------- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index ad01730ba9a32..7014a61a84c25 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -5548,18 +5548,6 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, interp_ins_set_sreg (td->last_ins, MINT_CALL_ARGS_SREG); td->last_ins->flags |= INTERP_INST_FLAG_CALL; td->last_ins->info.call_args = call_args; - } else if (m_class_get_image (klass) == mono_defaults.corlib && - !strcmp (m_class_get_name (m->klass), "ByReference") && - !strcmp (m->name, ".ctor")) { - /* public ByReference(ref T value) */ - MONO_PROFILER_RAISE (inline_method, (td->rtm->method, m)); - g_assert (csignature->hasthis && csignature->param_count == 1); - td->sp--; - /* We already have the vt on top of the stack. Just do a dummy mov that should be optimized out */ - interp_add_ins (td, MINT_MOV_P); - interp_ins_set_sreg (td->last_ins, td->sp [0].local); - push_type_vt (td, klass, mono_class_value_size (klass, NULL)); - interp_ins_set_dreg (td->last_ins, td->sp [-1].local); } else if (m_class_get_image (klass) == mono_defaults.corlib && (!strcmp (m_class_get_name (m->klass), "Span`1") || !strcmp (m_class_get_name (m->klass), "ReadOnlySpan`1")) && diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index e4e72be079ecf..53ccc077c0783 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -75,24 +75,12 @@ mono_type_is_native_blittable (MonoType *t) MonoInst* mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args) { - const char* cmethod_klass_name_space = m_class_get_name_space (cmethod->klass); - const char* cmethod_klass_name = m_class_get_name (cmethod->klass); - MonoImage *cmethod_klass_image = m_class_get_image (cmethod->klass); - gboolean in_corlib = cmethod_klass_image == mono_defaults.corlib; MonoInst *ins = NULL; /* Required intrinsics are always used even with -O=-intrins */ - if (in_corlib && - !strcmp (cmethod_klass_name_space, "System") && - !strcmp (cmethod_klass_name, "ByReference")) { - /* public ByReference(ref T value) */ - g_assert (fsig->hasthis && fsig->param_count == 1); - EMIT_NEW_STORE_MEMBASE (cfg, ins, OP_STORE_MEMBASE_REG, args [0]->dreg, 0, args [1]->dreg); - return ins; - } if (!(cfg->opt & MONO_OPT_INTRINS)) - return NULL; + return ins; #ifdef MONO_ARCH_SIMD_INTRINSICS if (cfg->opt & MONO_OPT_SIMD) { @@ -102,7 +90,7 @@ mini_emit_inst_for_ctor (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignat } #endif - return NULL; + return ins; } static MonoInst* From 362df634d3456b30d72bb7f78e1be82c3ceb0d2a Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 1 Jul 2022 20:16:11 -0700 Subject: [PATCH 20/22] Handle byref field in interpreter --- src/mono/mono/mini/interp/transform.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 7014a61a84c25..d5e64ac20578e 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -5824,6 +5824,12 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, int obj_size = mono_class_value_size (klass, NULL); obj_size = ALIGN_TO (obj_size, MINT_VT_ALIGNMENT); + if (m_type_is_byref (ftype)) { + // if it's a ref field in a struct, pretend its an unmanaged pointer + mt = MINT_TYPE_I; + field_size = SIZEOF_VOID_P; + field_klass = mono_defaults.int_class; // hack + } { if (is_static) { td->sp--; From b9f4948c8acba345bcca4c03d925b8b69fcef927 Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Fri, 1 Jul 2022 20:16:35 -0700 Subject: [PATCH 21/22] Fix build break when DEBUG_INTERP defined. --- src/mono/mono/mini/interp/interp.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/mono/mono/mini/interp/interp.c b/src/mono/mono/mini/interp/interp.c index ed3a579523e5a..6f998c81a6e91 100644 --- a/src/mono/mono/mini/interp/interp.c +++ b/src/mono/mono/mini/interp/interp.c @@ -3342,10 +3342,8 @@ static long opcode_counts[MINT_LASTOP]; if (tracing > 1) { \ output_indent (); \ char *mn = mono_method_full_name (frame->imethod->method, FALSE); \ - char *disasm = mono_interp_dis_mintop ((gint32)(ip - frame->imethod->code), TRUE, ip + 1, *ip); \ - g_print ("(%p) %s -> %s\n", mono_thread_internal_current (), mn, disasm); \ + g_print ("(%p) %s -> IL_%04x: %-10s\n", mono_thread_internal_current (), mn, (gint32)(ip - frame->imethod->code), mono_interp_opname (*ip)); \ g_free (mn); \ - g_free (disasm); \ } #else #define DUMP_INSTR() From 0d0c9de1eb6c5326d69ef6304c8dad6ef998833b Mon Sep 17 00:00:00 2001 From: Aaron Robinson Date: Sat, 2 Jul 2022 08:39:47 -0700 Subject: [PATCH 22/22] Feedback and build breaks. --- .../aot/ILCompiler.ReadyToRun/IBC/IBCProfileData.cs | 12 ++++++------ src/mono/mono/mini/interp/transform.c | 8 +------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileData.cs b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileData.cs index 266be8710eb0b..a36d77e8fe652 100644 --- a/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileData.cs +++ b/src/coreclr/tools/aot/ILCompiler.ReadyToRun/IBC/IBCProfileData.cs @@ -18,13 +18,13 @@ public class MibcConfig public override string ToString() { return - $""" - FormatVersion: {FormatVersion} - Runtime: {Runtime} - Os: {Os} - Arch: {Arch} +$@" +FormatVersion: {FormatVersion} +Runtime: {Runtime} +Os: {Os} +Arch: {Arch} - """; +"; } public static MibcConfig FromKeyValueMap(Dictionary kvMap) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index d5e64ac20578e..a65b355d996df 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -5819,17 +5819,11 @@ generate_code (TransformData *td, MonoMethod *method, MonoMethodHeader *header, mono_class_init_internal (klass); MonoClass *field_klass = mono_class_from_mono_type_internal (ftype); - mt = mint_type (m_class_get_byval_arg (field_klass)); + mt = mint_type (ftype); int field_size = mono_class_value_size (field_klass, NULL); int obj_size = mono_class_value_size (klass, NULL); obj_size = ALIGN_TO (obj_size, MINT_VT_ALIGNMENT); - if (m_type_is_byref (ftype)) { - // if it's a ref field in a struct, pretend its an unmanaged pointer - mt = MINT_TYPE_I; - field_size = SIZEOF_VOID_P; - field_klass = mono_defaults.int_class; // hack - } { if (is_static) { td->sp--;