Refactor Span<T> to ease implementation of JIT intrinsics (dotnet/coreclr#8497)
authorJan Kotas <jkotas@microsoft.com>
Wed, 7 Dec 2016 23:16:57 +0000 (15:16 -0800)
committerGitHub <noreply@github.com>
Wed, 7 Dec 2016 23:16:57 +0000 (15:16 -0800)
- Introduce internal ByReference<T> type for byref fields and change Span to use it
- Generalize handling of byref-like types in the type loader
- Make DangerousGetPinnableReference public while I was on it

Commit migrated from https://github.com/dotnet/coreclr/commit/64c2ad17351ac5bc0bb042216bfcbf1c5136d7cf

15 files changed:
src/coreclr/src/inc/dacvars.h
src/coreclr/src/mscorlib/model.xml
src/coreclr/src/mscorlib/mscorlib.shared.sources.props
src/coreclr/src/mscorlib/src/System/ByReference.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs
src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
src/coreclr/src/mscorlib/src/System/Span.cs
src/coreclr/src/vm/appdomain.cpp
src/coreclr/src/vm/classnames.h
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/methodtablebuilder.cpp
src/coreclr/src/vm/methodtablebuilder.h
src/coreclr/src/vm/mscorlib.h
src/coreclr/src/vm/vars.cpp
src/coreclr/src/vm/vars.hpp

index 4df2142..0a60684 100644 (file)
@@ -219,8 +219,7 @@ DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pArrayClass, ::g_pArrayClass)
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pSZArrayHelperClass, ::g_pSZArrayHelperClass)
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pNullableClass, ::g_pNullableClass)
 #ifdef FEATURE_SPAN_OF_T
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pSpanClass, ::g_pSpanClass)
-DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pReadOnlySpanClass, ::g_pReadOnlySpanClass)
+DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pByReferenceClass, ::g_pByReferenceClass)
 #endif
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pExceptionClass, ::g_pExceptionClass)
 DEFINE_DACVAR(ULONG, UNKNOWN_POINTER_TYPE, dac__g_pThreadAbortExceptionClass, ::g_pThreadAbortExceptionClass)
index 92ef0d9..b4cd2bd 100644 (file)
       <Member Name="#ctor(T[],System.Int32)" />
       <Member Name="#ctor(T[],System.Int32,System.Int32)" />
       <Member Name="#ctor(System.Void*,System.Int32)" />
+      <Member Name="DangerousGetPinnableReference" />
       <Member Name="op_Implicit(T[])" ReturnType="System.Span&lt;T&gt;" />
       <Member Name="op_Implicit(System.ArraySegment&lt;T&gt;)" ReturnType="System.Span&lt;T&gt;" />
       <Member Name="get_Length" />
       <Member Name="#ctor(T[],System.Int32)" />
       <Member Name="#ctor(T[],System.Int32,System.Int32)" />
       <Member Name="#ctor(System.Void*,System.Int32)" />
+      <Member Name="DangerousGetPinnableReference" />
       <Member Name="op_Implicit(System.Span&lt;T&gt;)" ReturnType="System.ReadOnlySpan&lt;T&gt;" />
       <Member Name="op_Implicit(T[])" ReturnType="System.ReadOnlySpan&lt;T&gt;" />
       <Member Name="op_Implicit(System.ArraySegment&lt;T&gt;)" ReturnType="System.ReadOnlySpan&lt;T&gt;" />
index 891f73c..8d4142e 100644 (file)
     <SystemSources Condition="'$(FeatureCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\__ComObject.cs" />
     <SystemSources Condition="'$(FeatureCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\Variant.cs" />
     <SystemSources Condition="'$(FeatureClassicCominterop)' == 'true'" Include="$(BclSourcesRoot)\System\OleAutBinder.cs" />
+    <SystemSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\ByReference.cs" />
     <SystemSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\Span.cs" />
     <SystemSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\ReadOnlySpan.cs" />
   </ItemGroup>
diff --git a/src/coreclr/src/mscorlib/src/System/ByReference.cs b/src/coreclr/src/mscorlib/src/System/ByReference.cs
new file mode 100644 (file)
index 0000000..6f8bb22
--- /dev/null
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.CompilerServices;
+
+namespace System
+{
+    // ByReference<T> 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.
+    internal struct ByReference<T>
+    {
+        private IntPtr _value;
+
+        public ByReference(ref T value)
+        {
+            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
+            unsafe { _value = (IntPtr)Unsafe.AsPointer(ref value); }
+        }
+
+        public ref T Value
+        {
+            get
+            {
+                // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
+                unsafe { return ref Unsafe.As<IntPtr, T>(ref *(IntPtr*)_value); }
+            }
+        }
+    }
+}
index e94d353..9235fcf 100644 (file)
@@ -13,10 +13,10 @@ namespace System
     /// characteristics on par with T[]. Unlike arrays, it can point to either managed
     /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
     /// </summary>
-    public unsafe struct ReadOnlySpan<T>
+    public struct ReadOnlySpan<T>
     {
-        /// <summary>A byref or a native ptr. Do not access directly</summary>
-        private readonly IntPtr _rawPointer;
+        /// <summary>A byref or a native ptr.</summary>
+        private readonly ByReference<T> _pointer;
         /// <summary>The number of elements this ReadOnlySpan contains.</summary>
         private readonly int _length;
 
@@ -31,8 +31,7 @@ namespace System
             if (array == null)
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
 
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref JitHelpers.GetArrayData(array));
+            _pointer = new ByReference<T>(ref JitHelpers.GetArrayData(array));
             _length = array.Length;
         }
 
@@ -54,8 +53,7 @@ namespace System
             if ((uint)start > (uint)array.Length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
             _length = array.Length - start;
         }
 
@@ -78,8 +76,7 @@ namespace System
             if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
             _length = length;
         }
 
@@ -105,7 +102,7 @@ namespace System
             if (length < 0)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            _rawPointer = (IntPtr)pointer;
+            _pointer = new ByReference<T>(ref Unsafe.AsRef<T>(pointer));
             _length = length;
         }
 
@@ -114,18 +111,17 @@ namespace System
         /// </summary>
         internal ReadOnlySpan(ref T ptr, int length)
         {
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref ptr);
+            _pointer = new ByReference<T>(ref ptr);
             _length = length;
         }
 
         /// <summary>
-        /// An internal helper for accessing spans.
+        /// 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 can be used for pinning but must never be dereferenced.
         /// </summary>
-        internal unsafe ref T GetRawPointer()
+        public ref T DangerousGetPinnableReference()
         {
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            return ref Unsafe.As<IntPtr, T>(ref *(IntPtr *)_rawPointer);
+            return ref _pointer.Value;
         }
 
         /// <summary>
@@ -133,7 +129,7 @@ namespace System
         /// </summary>
         public static implicit operator ReadOnlySpan<T>(Span<T> slice)
         {
-            return new ReadOnlySpan<T>(ref slice.GetRawPointer(), slice.Length);
+            return new ReadOnlySpan<T>(ref slice.DangerousGetPinnableReference(), slice.Length);
         }
 
         /// <summary>
@@ -189,7 +185,7 @@ namespace System
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                return Unsafe.Add(ref GetRawPointer(), index);
+                return Unsafe.Add(ref DangerousGetPinnableReference(), index);
             }
         }
 
@@ -204,7 +200,7 @@ namespace System
                 return Array.Empty<T>();
 
             var destination = new T[_length];
-            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref GetRawPointer(), _length);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
             return destination;
         }
 
@@ -221,7 +217,7 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref Unsafe.Add(ref GetRawPointer(), start), _length - start);
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
         }
 
         /// <summary>
@@ -238,7 +234,7 @@ namespace System
             if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref Unsafe.Add(ref GetRawPointer(), start), length);
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
         }
 
         /// <summary>
@@ -248,7 +244,7 @@ namespace System
         public bool Equals(ReadOnlySpan<T> other)
         {
             return (_length == other.Length) &&
-                (_length == 0 || Unsafe.AreSame(ref GetRawPointer(), ref other.GetRawPointer()));
+                (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference()));
         }
 
         /// <summary>
@@ -261,7 +257,7 @@ namespace System
             if ((uint)_length > (uint)destination.Length)
                 return false;
 
-            SpanHelper.CopyTo<T>(ref destination.GetRawPointer(), ref GetRawPointer(), _length);
+            SpanHelper.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length);
             return true;
         }
     }
index 70d8ec0..db3b2f2 100644 (file)
@@ -23,7 +23,7 @@ namespace System.Runtime.CompilerServices
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static void* AsPointer<T>(ref T value)
         {
-            // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
+            // The body of this function will be replaced by the EE with unsafe code!!!
             // See getILIntrinsicImplementationForUnsafe for how this happens.  
             throw new InvalidOperationException();
         }
@@ -41,13 +41,25 @@ namespace System.Runtime.CompilerServices
         }
 
         /// <summary>
+        /// Reinterprets the given location as a reference to a value of type<typeparamref name="T"/>.
+        /// </summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ref T AsRef<T>(void * source)
+        {
+            // The body of this function will be replaced by the EE with unsafe code!!!
+            // See getILIntrinsicImplementationForUnsafe for how this happens.  
+            throw new InvalidOperationException();
+        }
+
+        /// <summary>
         /// Reinterprets the given reference as a reference to a value of type <typeparamref name="TTo"/>.
         /// </summary>
         [NonVersionable]
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static ref TTo As<TFrom, TTo>(ref TFrom source)
         {
-            // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
+            // The body of this function will be replaced by the EE with unsafe code!!!
             // See getILIntrinsicImplementationForUnsafe for how this happens.  
             throw new InvalidOperationException();
         }
index 2eff6ae..21785cd 100644 (file)
@@ -13,10 +13,10 @@ namespace System
     /// characteristics on par with T[]. Unlike arrays, it can point to either managed
     /// or native memory, or to memory allocated on the stack. It is type- and memory-safe.
     /// </summary>
-    public unsafe struct Span<T>
+    public struct Span<T>
     {
-        /// <summary>A byref or a native ptr. Do not access directly</summary>
-        private readonly IntPtr _rawPointer;
+        /// <summary>A byref or a native ptr.</summary>
+        private readonly ByReference<T> _pointer;
         /// <summary>The number of elements this Span contains.</summary>
         private readonly int _length;
 
@@ -36,8 +36,7 @@ namespace System
                     ThrowHelper.ThrowArrayTypeMismatchException();
             }
 
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref JitHelpers.GetArrayData(array));
+            _pointer = new ByReference<T>(ref JitHelpers.GetArrayData(array));
             _length = array.Length;
         }
 
@@ -64,8 +63,7 @@ namespace System
             if ((uint)start > (uint)array.Length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
             _length = array.Length - start;
         }
 
@@ -93,8 +91,7 @@ namespace System
             if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
+            _pointer = new ByReference<T>(ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
             _length = length;
         }
 
@@ -120,7 +117,7 @@ namespace System
             if (length < 0)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            _rawPointer = (IntPtr)pointer;
+            _pointer = new ByReference<T>(ref Unsafe.AsRef<T>(pointer));
             _length = length;
         }
 
@@ -129,18 +126,17 @@ namespace System
         /// </summary>
         internal Span(ref T ptr, int length)
         {
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            _rawPointer = (IntPtr)Unsafe.AsPointer(ref ptr);
+            _pointer = new ByReference<T>(ref ptr);
             _length = length;
         }
 
         /// <summary>
-        /// An internal helper for accessing spans.
+        /// 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 can be used for pinning but must never be dereferenced.
         /// </summary>
-        internal unsafe ref T GetRawPointer()
+        public ref T DangerousGetPinnableReference()
         {
-            // TODO-SPAN: This has GC hole. It needs to be JIT intrinsic instead
-            return ref Unsafe.As<IntPtr, T>(ref *(IntPtr*)_rawPointer);
+            return ref _pointer.Value;
         }
 
         /// <summary>
@@ -196,14 +192,14 @@ namespace System
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                return Unsafe.Add(ref GetRawPointer(), index);
+                return Unsafe.Add(ref DangerousGetPinnableReference(), index);
             }
             set
             {
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                Unsafe.Add(ref GetRawPointer(), index) = value;
+                Unsafe.Add(ref DangerousGetPinnableReference(), index) = value;
             }
         }
 
@@ -218,7 +214,7 @@ namespace System
                 return Array.Empty<T>();
 
             var destination = new T[_length];
-            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref GetRawPointer(), _length);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
             return destination;
         }
 
@@ -235,7 +231,7 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new Span<T>(ref Unsafe.Add(ref GetRawPointer(), start), _length - start);
+            return new Span<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
         }
 
         /// <summary>
@@ -252,7 +248,7 @@ namespace System
             if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new Span<T>(ref Unsafe.Add(ref GetRawPointer(), start), length);
+            return new Span<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
         }
 
         /// <summary>
@@ -262,7 +258,7 @@ namespace System
         public bool Equals(Span<T> other)
         {
             return (_length == other.Length) &&
-                (_length == 0 || Unsafe.AreSame(ref GetRawPointer(), ref other.GetRawPointer()));
+                (_length == 0 || Unsafe.AreSame(ref DangerousGetPinnableReference(), ref other.DangerousGetPinnableReference()));
         }
 
         /// <summary>
@@ -275,7 +271,7 @@ namespace System
             if ((uint)_length > (uint)destination.Length)
                 return false;
 
-            SpanHelper.CopyTo<T>(ref destination.GetRawPointer(), ref GetRawPointer(), _length);
+            SpanHelper.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length);
             return true;
         }
 
@@ -287,7 +283,7 @@ namespace System
             if ((uint)values.Length > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            SpanHelper.CopyTo<T>(ref GetRawPointer(), ref values.GetRawPointer(), values.Length);
+            SpanHelper.CopyTo<T>(ref DangerousGetPinnableReference(), ref values.DangerousGetPinnableReference(), values.Length);
         }
     }
 
@@ -308,7 +304,7 @@ namespace System
                 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
 
             return new Span<byte>(
-                ref Unsafe.As<T, byte>(ref source.GetRawPointer()),
+                ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference()),
                 checked(source.Length * Unsafe.SizeOf<T>()));
         }
 
@@ -327,7 +323,7 @@ namespace System
                 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(T));
 
             return new ReadOnlySpan<byte>(
-                ref Unsafe.As<T, byte>(ref source.GetRawPointer()),
+                ref Unsafe.As<T, byte>(ref source.DangerousGetPinnableReference()),
                 checked(source.Length * Unsafe.SizeOf<T>()));
         }
 
@@ -342,7 +338,7 @@ namespace System
         /// <exception cref="System.ArgumentException">
         /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
         /// </exception>
-        public static unsafe Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
+        public static Span<TTo> NonPortableCast<TFrom, TTo>(this Span<TFrom> source)
             where TFrom : struct
             where TTo : struct
         {
@@ -352,7 +348,7 @@ namespace System
                 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
 
             return new Span<TTo>(
-                ref Unsafe.As<TFrom, TTo>(ref source.GetRawPointer()),
+                ref Unsafe.As<TFrom, TTo>(ref source.DangerousGetPinnableReference()),
                 checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
         }
 
@@ -367,7 +363,7 @@ namespace System
         /// <exception cref="System.ArgumentException">
         /// Thrown when <typeparamref name="TFrom"/> or <typeparamref name="TTo"/> contains pointers.
         /// </exception>
-        public static unsafe ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
+        public static ReadOnlySpan<TTo> NonPortableCast<TFrom, TTo>(this ReadOnlySpan<TFrom> source)
             where TFrom : struct
             where TTo : struct
         {
@@ -377,7 +373,7 @@ namespace System
                 ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(typeof(TTo));
 
             return new ReadOnlySpan<TTo>(
-                ref Unsafe.As<TFrom, TTo>(ref source.GetRawPointer()),
+                ref Unsafe.As<TFrom, TTo>(ref source.DangerousGetPinnableReference()),
                 checked((int)((long)source.Length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
         }
     }
index 0ee260e..b7fc67c 100644 (file)
@@ -2871,9 +2871,8 @@ void SystemDomain::LoadBaseSystemClasses()
     g_pSZArrayHelperClass = MscorlibBinder::GetClass(CLASS__SZARRAYHELPER);
 
 #ifdef FEATURE_SPAN_OF_T
-    // Load Span class
-    g_pSpanClass = MscorlibBinder::GetClass(CLASS__SPAN);
-    g_pReadOnlySpanClass = MscorlibBinder::GetClass(CLASS__READONLY_SPAN);
+    // Load ByReference class
+    g_pByReferenceClass = MscorlibBinder::GetClass(CLASS__BYREFERENCE);
 #endif
 
     // Load Nullable class
index ec5486a..47f1fec 100644 (file)
@@ -17,8 +17,7 @@
 
 #define g_NullableName "Nullable`1"
 #ifdef FEATURE_SPAN_OF_T
-#define g_SpanName "Span`1"
-#define g_ReadOnlySpanName "ReadOnlySpan`1"
+#define g_ByReferenceName "ByReference`1"
 #endif
 
 #define g_CollectionsEnumerableItfName "System.Collections.IEnumerable"
index fac4cb4..cebd410 100644 (file)
@@ -2303,13 +2303,9 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
 
     MethodTable* pMT = VMClsHnd.GetMethodTable();
 
-    if (pMT == g_TypedReferenceMT) // if (pMT->IsByRefLike()) // TODO-SPAN: Proper GC reporting
+    if (pMT->IsByRefLike())
     {
-        if (pMT == g_TypedReferenceMT
-#ifdef FEATURE_SPAN_OF_T
-            || pMT->HasSameTypeDefAs(g_pSpanClass) || pMT->HasSameTypeDefAs(g_pReadOnlySpanClass)
-#endif
-            )
+        if (pMT == g_TypedReferenceMT)
         {
             gcPtrs[0] = TYPE_GC_BYREF;
             gcPtrs[1] = TYPE_GC_NONE;
@@ -2317,6 +2313,9 @@ unsigned CEEInfo::getClassGClayout (CORINFO_CLASS_HANDLE clsHnd, BYTE* gcPtrs)
         }
         else
         {
+            // TODO-SPAN: Proper GC reporting
+            memset(gcPtrs, TYPE_GC_NONE,
+                   (VMClsHnd.GetSize() + sizeof(void*) -1)/ sizeof(void*));
             result = 0;
         }
     }
@@ -7034,7 +7033,9 @@ bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
         methInfo->options = (CorInfoOptions)0;
         return true;
     }
-    else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef())
+    else if ((tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__AS_REF)->GetMemberDef()) ||
+             (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef()))
+             
     {
         // Return the argument that was passed in.
         static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
index ab55f11..682268e 100644 (file)
@@ -1862,6 +1862,11 @@ MethodTableBuilder::BuildMethodTableThrowing(
         pMT->SetHasBoxedRegularStatics();
     }
 
+    if (bmtFP->fIsByRefLikeType)
+    {
+        pMT->SetIsByRefLike();
+    }
+
     if (IsValueClass())
     {
         if (bmtFP->NumInstanceFieldBytes != totalDeclaredFieldSize || HasOverLayedField())
@@ -4214,14 +4219,12 @@ VOID    MethodTableBuilder::InitializeFieldDescs(FieldDesc *pFieldDescList,
                     goto GOT_ELEMENT_TYPE;
                 }
                 
-                // There are just few types with code:IsByRefLike set - see code:CheckForSystemTypes.
-                // Note: None of them will ever have self-referencing static ValueType field (we cannot assert it now because the IsByRefLike 
-                // status for this type has not been initialized yet).
+                // Inherit IsByRefLike characteristic from fields
                 if (!IsSelfRef(pByValueClass) && pByValueClass->IsByRefLike())
-                {   // Cannot have embedded valuetypes that contain a field that require stack allocation.
-                    BuildMethodTableThrowException(COR_E_BADIMAGEFORMAT, IDS_CLASSLOAD_BAD_FIELD, mdTokenNil);
+                {
+                    bmtFP->fIsByRefLikeType = true;
                 }
-                
+
                 if (!IsSelfRef(pByValueClass) && pByValueClass->GetClass()->HasNonPublicFields())
                 {   // If a class has a field of type ValueType with non-public fields in it,
                     // the class must "inherit" this characteristic
@@ -10207,19 +10210,10 @@ void MethodTableBuilder::CheckForSystemTypes()
     if (bmtGenerics->HasInstantiation() && g_pNullableClass != NULL)
     {
 #ifdef FEATURE_SPAN_OF_T
-        _ASSERTE(g_pSpanClass != NULL);
-        _ASSERTE(g_pReadOnlySpanClass != NULL);
-
-        _ASSERTE(g_pSpanClass->IsByRefLike());
-        _ASSERTE(g_pReadOnlySpanClass->IsByRefLike());
+        _ASSERTE(g_pByReferenceClass != NULL);
+        _ASSERTE(g_pByReferenceClass->IsByRefLike());
 
-        if (GetCl() == g_pSpanClass->GetCl())
-        {
-            pMT->SetIsByRefLike();
-            return;
-        }
-
-        if (GetCl() == g_pReadOnlySpanClass->GetCl())
+        if (GetCl() == g_pByReferenceClass->GetCl())
         {
             pMT->SetIsByRefLike();
             return;
@@ -10281,11 +10275,7 @@ void MethodTableBuilder::CheckForSystemTypes()
             pMT->SetIsNullable();
         }
 #ifdef FEATURE_SPAN_OF_T
-        else if (strcmp(name, g_SpanName) == 0)
-        {
-            pMT->SetIsByRefLike();
-        }
-        else if (strcmp(name, g_ReadOnlySpanName) == 0)
+        else if (strcmp(name, g_ByReferenceName) == 0)
         {
             pMT->SetIsByRefLike();
         }
index 1e40ea9..1cf7149 100644 (file)
@@ -2081,6 +2081,7 @@ private:
         DWORD NumGCPointerSeries;
         DWORD NumInstanceFieldBytes;
 
+        bool  fIsByRefLikeType;
         bool  fHasFixedAddressValueTypes;
         bool  fHasSelfReferencingStaticValueTypeField_WithRVA;
 
index c145e4d..7a0b1a0 100644 (file)
@@ -1053,6 +1053,7 @@ DEFINE_FIELD(NULL,                  VALUE,          Value)
 DEFINE_CLASS(NULLABLE,              System,                 Nullable`1)
 
 #ifdef FEATURE_SPAN_OF_T
+DEFINE_CLASS(BYREFERENCE,           System,                 ByReference`1)
 DEFINE_CLASS(SPAN,                  System,                 Span`1)
 DEFINE_CLASS(READONLY_SPAN,         System,                 ReadOnlySpan`1)
 #endif
@@ -1352,6 +1353,7 @@ DEFINE_METHOD(JIT_HELPERS,          CONTAINSREFERENCES,     ContainsReferences,
 DEFINE_CLASS(UNSAFE,                CompilerServices,       Unsafe)
 DEFINE_METHOD(UNSAFE,               AS_POINTER,             AsPointer, NoSig)
 DEFINE_METHOD(UNSAFE,               SIZEOF,                 SizeOf, NoSig)
+DEFINE_METHOD(UNSAFE,               AS_REF,                 AsRef, NoSig)
 DEFINE_METHOD(UNSAFE,               BYREF_AS,               As, NoSig)
 DEFINE_METHOD(UNSAFE,               BYREF_ADD,              Add, NoSig)
 DEFINE_METHOD(UNSAFE,               BYREF_ARE_SAME,         AreSame, NoSig)
index 8d19a5c..626ca3c 100644 (file)
@@ -70,8 +70,7 @@ GPTR_IMPL(MethodTable,      g_pArrayClass);
 GPTR_IMPL(MethodTable,      g_pSZArrayHelperClass);
 GPTR_IMPL(MethodTable,      g_pNullableClass);
 #ifdef FEATURE_SPAN_OF_T
-GPTR_IMPL(MethodTable,      g_pSpanClass);
-GPTR_IMPL(MethodTable,      g_pReadOnlySpanClass);
+GPTR_IMPL(MethodTable,      g_pByReferenceClass);
 #endif
 GPTR_IMPL(MethodTable,      g_pExceptionClass);
 GPTR_IMPL(MethodTable,      g_pThreadAbortExceptionClass);
index 712543c..62d6656 100644 (file)
@@ -403,8 +403,7 @@ GPTR_DECL(MethodTable,      g_pArrayClass);
 GPTR_DECL(MethodTable,      g_pSZArrayHelperClass);
 GPTR_DECL(MethodTable,      g_pNullableClass);
 #ifdef FEATURE_SPAN_OF_T
-GPTR_DECL(MethodTable,      g_pSpanClass);
-GPTR_DECL(MethodTable,      g_pReadOnlySpanClass);
+GPTR_DECL(MethodTable,      g_pByReferenceClass);
 #endif
 GPTR_DECL(MethodTable,      g_pExceptionClass);
 GPTR_DECL(MethodTable,      g_pThreadAbortExceptionClass);