Streamline implementation of ToArray to call CopyTo<T> directly
authorJan Kotas <jkotas@microsoft.com>
Sun, 30 Oct 2016 08:50:27 +0000 (01:50 -0700)
committerJan Kotas <jkotas@microsoft.com>
Mon, 31 Oct 2016 00:27:55 +0000 (17:27 -0700)
Fix missing pinning in CopyTo<T>
Move and rename some JitHelpers to S.R.CS.Unsafe to make different implementations more similar

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

src/coreclr/src/mscorlib/mscorlib.shared.sources.props
src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs
src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs [new file with mode: 0644]
src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/jithelpers.cs
src/coreclr/src/mscorlib/src/System/Span.cs
src/coreclr/src/vm/jitinterface.cpp
src/coreclr/src/vm/mscorlib.h

index 2f7a616..d86a2dc 100644 (file)
@@ -24,6 +24,7 @@
     <CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\TypeDependencyAttribute.cs" />
     <CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\CompilerMarshalOverride.cs" />
     <CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\jithelpers.cs" />
+    <CompilerServicesSources Condition="'$(FeatureSpanOfT)' == 'true'" Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\Unsafe.cs" />
     <CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\SpecialNameAttribute.cs" />
     <CompilerServicesSources Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\SuppressMergeCheckAttribute.cs" />
     <CompilerServicesSources Condition="'$(FeatureICastable)' == 'true'" Include="$(BclSourcesRoot)\System\Runtime\CompilerServices\ICastable.cs" />
index bf4216d..853c68f 100644 (file)
@@ -55,7 +55,7 @@ namespace System
             if ((uint)start >= (uint)array.Length || (uint)length > (uint)(array.Length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            JitHelpers.SetByRef(out _rawPointer, ref JitHelpers.AddByRef(ref JitHelpers.GetArrayData(array), start));
+            JitHelpers.SetByRef(out _rawPointer, ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
             _length = length;
         }
 
@@ -96,7 +96,7 @@ namespace System
 
         public static implicit operator ReadOnlySpan<T>(Span<T> slice)
         {
-            return new ReadOnlySpan<T>(ref JitHelpers.GetByRef<T>(ref slice._rawPointer), slice.Length);
+            return new ReadOnlySpan<T>(ref JitHelpers.GetByRef<T>(ref slice._rawPointer), slice._length);
         }
 
         public static implicit operator ReadOnlySpan<T>(T[] array)
@@ -137,7 +137,7 @@ namespace System
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                return JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
+                return Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
             }
         }
 
@@ -148,8 +148,11 @@ namespace System
         /// </summary>
         public T[] ToArray()
         {
+            if (_length == 0)
+                return Array.Empty<T>();
+
             var destination = new T[_length];
-            TryCopyTo(destination);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
             return destination;
         }
 
@@ -165,7 +168,7 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), Length - start);
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), _length - start);
         }
 
         /// <summary>
@@ -181,7 +184,7 @@ namespace System
             if ((uint)start >= (uint)_length || (uint)length > (uint)(_length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
         }
 
         /// <summary>
@@ -191,7 +194,7 @@ namespace System
         public bool Equals(ReadOnlySpan<T> other)
         {
             return (_length == other._length) &&
-                (_length == 0 || JitHelpers.ByRefEquals(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
+                (_length == 0 || Unsafe.AreSame(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
         }
 
         /// <summary>
@@ -201,10 +204,10 @@ namespace System
         /// <param name="destination">The span to copy items into.</param>
         public bool TryCopyTo(Span<T> destination)
         {
-            if (Length > destination.Length)
+            if (_length > destination._length)
                 return false;
 
-            SpanHelper.CopyTo<T>(ref destination._rawPointer, ref _rawPointer, Length);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetByRef<T>(ref destination._rawPointer), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
             return true;
         }
     }
@@ -242,7 +245,7 @@ namespace System
             if ((uint)start > (uint)text.Length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<char>(ref JitHelpers.AddByRef(ref text.GetFirstCharRef(), start), text.Length - start);
+            return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetFirstCharRef(), start), text.Length - start);
         }
 
         /// <summary>
@@ -263,7 +266,7 @@ namespace System
             if ((uint)start >= (uint)text.Length || (uint)length > (uint)(text.Length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<char>(ref JitHelpers.AddByRef(ref text.GetFirstCharRef(), start), length);
+            return new ReadOnlySpan<char>(ref Unsafe.Add(ref text.GetFirstCharRef(), start), length);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs b/src/coreclr/src/mscorlib/src/System/Runtime/CompilerServices/Unsafe.cs
new file mode 100644 (file)
index 0000000..3ebc321
--- /dev/null
@@ -0,0 +1,68 @@
+// 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.Versioning;
+
+namespace System.Runtime.CompilerServices
+{
+    //
+    // Subsetted clone of System.Runtime.CompilerServices.Unsafe for internal runtime use.
+    // Keep in sync with https://github.com/dotnet/corefx/tree/master/src/System.Runtime.CompilerServices.Unsafe.
+    // 
+
+    /// <summary>
+    /// Contains generic, low-level functionality for manipulating pointers.
+    /// </summary>
+    internal static class Unsafe
+    {
+        /// <summary>
+        /// Returns the size of an object of the given type parameter.
+        /// </summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static int SizeOf<T>()
+        {
+            // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
+            // See getILIntrinsicImplementation 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
+            // See getILIntrinsicImplementation for how this happens.  
+            throw new InvalidOperationException();
+        }
+
+        /// <summary>
+        /// Adds an element offset to the given reference.
+        /// </summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ref T Add<T>(ref T source, int elementOffset)
+        {
+            // The body of this function will be replaced by the EE with unsafe code!!!
+            // See getILIntrinsicImplementation for how this happens.
+            typeof(T).ToString(); // Type used by the actual method body
+            throw new InvalidOperationException();
+        }
+
+        /// <summary>
+        /// Determines whether the specified references point to the same location.
+        /// </summary>
+        [NonVersionable]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static bool AreSame<T>(ref T left, ref T right)
+        {
+            // The body of this function will be replaced by the EE with unsafe code!!!
+            // See getILIntrinsicImplementation for how this happens.  
+            throw new InvalidOperationException();
+        }
+    }
+}
index 9cafc68..1ad7899 100644 (file)
@@ -242,21 +242,6 @@ namespace System.Runtime.CompilerServices {
             throw new InvalidOperationException();
         }
 
-        static internal ref T AddByRef<T>(ref T pointer, int count)
-        {
-            // The body of this function will be replaced by the EE with unsafe code!!!
-            // See getILIntrinsicImplementation for how this happens.
-            typeof(T).ToString(); // Type used by the actual method body
-            throw new InvalidOperationException();
-        }
-
-        static internal bool ByRefEquals<T>(ref T refA, ref T refB)
-        {
-            // The body of this function will be replaced by the EE with unsafe code!!!
-            // See getILIntrinsicImplementation for how this happens.  
-            throw new InvalidOperationException();
-        }
-
         static internal bool ByRefLessThan<T>(ref T refA, ref T refB)
         {
             // The body of this function will be replaced by the EE with unsafe code!!!
@@ -264,13 +249,6 @@ namespace System.Runtime.CompilerServices {
             throw new InvalidOperationException();
         }
 
-        static internal int SizeOf<T>()
-        {
-            // The body of this function will be replaced by the EE with unsafe code that just returns sizeof !!T
-            // See getILIntrinsicImplementation for how this happens.  
-            throw new InvalidOperationException();
-        }
-
         /// <returns>true if given type is reference type or value type that contains references</returns>
         static internal bool ContainsReferences<T>()
         {
index ee1c97e..2ef49fc 100644 (file)
@@ -65,7 +65,7 @@ namespace System
             if ((uint)start >= (uint)array.Length || (uint)length > (uint)(array.Length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            JitHelpers.SetByRef(out _rawPointer, ref JitHelpers.AddByRef(ref JitHelpers.GetArrayData(array), start));
+            JitHelpers.SetByRef(out _rawPointer, ref Unsafe.Add(ref JitHelpers.GetArrayData(array), start));
             _length = length;
         }
 
@@ -142,14 +142,14 @@ namespace System
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                return JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
+                return Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), index);
             }
             set
             {
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), index) = value;
+                Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), index) = value;
             }
         }
 
@@ -160,8 +160,11 @@ namespace System
         /// </summary>
         public T[] ToArray()
         {
+            if (_length == 0)
+                return Array.Empty<T>();
+
             var destination = new T[_length];
-            TryCopyTo(destination);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
             return destination;
         }
 
@@ -177,7 +180,7 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new Span<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), Length - start);
+            return new Span<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), _length - start);
         }
 
         /// <summary>
@@ -193,7 +196,7 @@ namespace System
             if ((uint)start >= (uint)_length || (uint)length > (uint)(_length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new Span<T>(ref JitHelpers.AddByRef(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
+            return new Span<T>(ref Unsafe.Add(ref JitHelpers.GetByRef<T>(ref _rawPointer), start), length);
         }
 
         /// <summary>
@@ -203,7 +206,7 @@ namespace System
         public bool Equals(Span<T> other)
         {
             return (_length == other._length) &&
-                (_length == 0 || JitHelpers.ByRefEquals(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
+                (_length == 0 || Unsafe.AreSame(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref other._rawPointer)));
         }
 
         /// <summary>
@@ -216,7 +219,7 @@ namespace System
             if (Length > destination.Length)
                 return false;
 
-            SpanHelper.CopyTo<T>(ref destination._rawPointer, ref _rawPointer, Length);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetByRef<T>(ref destination._rawPointer), ref JitHelpers.GetByRef<T>(ref _rawPointer), _length);
             return true;
         }
 
@@ -228,7 +231,7 @@ namespace System
             if ((uint)values._length > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            SpanHelper.CopyTo<T>(ref _rawPointer, ref values._rawPointer, values.Length);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetByRef<T>(ref _rawPointer), ref JitHelpers.GetByRef<T>(ref values._rawPointer), values._length);
         }
     }
 
@@ -250,7 +253,7 @@ namespace System
 
             return new Span<byte>(
                 ref JitHelpers.GetByRef<byte>(ref source._rawPointer),
-                checked((int)(source._length * JitHelpers.SizeOf<T>())));
+                checked((int)(source._length * Unsafe.SizeOf<T>())));
         }
 
         /// <summary>
@@ -269,7 +272,7 @@ namespace System
 
             return new ReadOnlySpan<byte>(
                 ref JitHelpers.GetByRef<byte>(ref source._rawPointer),
-                checked((int)(source._length * JitHelpers.SizeOf<T>())));
+                checked((int)(source._length * Unsafe.SizeOf<T>())));
         }
 
         /// <summary>
@@ -294,7 +297,7 @@ namespace System
 
             return new Span<TTo>(
                 ref JitHelpers.GetByRef<TTo>(ref source._rawPointer),
-                checked((int)(source._length * JitHelpers.SizeOf<TFrom>() / JitHelpers.SizeOf<TTo>())));
+                checked((int)(source._length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
         }
 
         /// <summary>
@@ -319,51 +322,47 @@ namespace System
 
             return new ReadOnlySpan<TTo>(
                 ref JitHelpers.GetByRef<TTo>(ref source._rawPointer),
-                checked((int)(source._length * JitHelpers.SizeOf<TFrom>() / JitHelpers.SizeOf<TTo>())));
+                checked((int)(source._length * Unsafe.SizeOf<TFrom>() / Unsafe.SizeOf<TTo>())));
         }
     }
 
     internal static class SpanHelper
     {
-        internal static void CopyTo<T>(ref IntPtr destination, ref IntPtr source, int elementsCount)
+        internal static unsafe void CopyTo<T>(ref T destination, ref T source, int elementsCount)
         {
             if (elementsCount == 0)
                 return;
 
-            ref T dest = ref JitHelpers.GetByRef<T>(ref destination);
-            ref T src = ref JitHelpers.GetByRef<T>(ref source);
-            if (JitHelpers.ByRefEquals(ref dest, ref src))
+            if (Unsafe.AreSame(ref destination, ref source))
                 return;
 
             if (!JitHelpers.ContainsReferences<T>())
             {
-                unsafe
+                fixed (byte* pDestination = &Unsafe.As<T, byte>(ref destination))
                 {
-                    Memmove<T>((byte*)destination, (byte*)source, elementsCount);
+                    fixed (byte* pSource = &Unsafe.As<T, byte>(ref source))
+                    {
+#if BIT64
+                        Buffer.Memmove(pDestination, pSource, (ulong)elementsCount * (ulong)Unsafe.SizeOf<T>());
+#else
+                        Buffer.Memmove(pDestination, pSource, (uint)elementsCount * (uint)Unsafe.SizeOf<T>());
+#endif
+                    }
                 }
             }
             else
             {
-                if (JitHelpers.ByRefLessThan(ref dest, ref src)) // copy forward
+                if (JitHelpers.ByRefLessThan(ref destination, ref source)) // copy forward
                 {
                     for (int i = 0; i < elementsCount; i++)
-                        JitHelpers.AddByRef(ref dest, i) = JitHelpers.AddByRef(ref src, i);
+                        Unsafe.Add(ref destination, i) = Unsafe.Add(ref source, i);
                 }
                 else // copy backward to avoid overlapping issues
                 {
                     for (int i = elementsCount - 1; i >= 0; i--)
-                        JitHelpers.AddByRef(ref dest, i) = JitHelpers.AddByRef(ref src, i);
+                        Unsafe.Add(ref destination, i) = Unsafe.Add(ref source, i);
                 }
             }
         }
-
-        private static unsafe void Memmove<T>(byte* destination, byte* source, int elementsCount)
-        {
-#if BIT64
-            Buffer.Memmove(destination, source, (ulong)elementsCount * (ulong)JitHelpers.SizeOf<T>());
-#else
-            Buffer.Memmove(destination, source, (uint)elementsCount * (uint)JitHelpers.SizeOf<T>());
-#endif
-        }
     }
-}
\ No newline at end of file
+}
index 36c10a7..f7730dd 100644 (file)
@@ -6934,41 +6934,6 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
         methInfo->options = (CorInfoOptions)0;
         return true;
     }
-    else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__ADD_BYREF)->GetMemberDef())
-    {
-        mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
-
-        static BYTE ilcode[] = { CEE_LDARG_1,
-                                 CEE_PREFIX1,(BYTE)CEE_SIZEOF,0,0,0,0,
-                                 CEE_CONV_I,
-                                 CEE_MUL,
-                                 CEE_LDARG_0,
-                                 CEE_ADD,
-                                 CEE_RET };
-
-        ilcode[3] = (BYTE)(tokGenericArg);
-        ilcode[4] = (BYTE)(tokGenericArg >> 8);
-        ilcode[5] = (BYTE)(tokGenericArg >> 16);
-        ilcode[6] = (BYTE)(tokGenericArg >> 24);
-
-        methInfo->ILCode = const_cast<BYTE*>(ilcode);
-        methInfo->ILCodeSize = sizeof(ilcode);
-        methInfo->maxStack = 2;
-        methInfo->EHcount = 0;
-        methInfo->options = (CorInfoOptions)0;
-        return true;
-    }
-    else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__BYREF_EQUALS)->GetMemberDef())
-    {
-        // Compare the two arguments
-        static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (BYTE)CEE_CEQ, CEE_RET };
-        methInfo->ILCode = const_cast<BYTE*>(ilcode);
-        methInfo->ILCodeSize = sizeof(ilcode);
-        methInfo->maxStack = 2;
-        methInfo->EHcount = 0;
-        methInfo->options = (CorInfoOptions)0;
-        return true;
-    }
     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__BYREF_LESSTHAN)->GetMemberDef())
     {
         // Compare the two arguments
@@ -7000,24 +6965,6 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
         methInfo->options = (CorInfoOptions)0;
         return true;
     }
-    else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__SIZEOF)->GetMemberDef())
-    {
-        _ASSERTE(ftn->HasMethodInstantiation());
-        Instantiation inst = ftn->GetMethodInstantiation();
-
-        _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
-        mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
-
-        static const BYTE ilcode[] = { CEE_PREFIX1, (BYTE)CEE_SIZEOF, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
-                                       CEE_RET }; 
-
-        methInfo->ILCode = const_cast<BYTE*>(ilcode);
-        methInfo->ILCodeSize = sizeof(ilcode);
-        methInfo->maxStack = 1;
-        methInfo->EHcount = 0;
-        methInfo->options = (CorInfoOptions)0;
-        return true;
-    }
     else if (tk == MscorlibBinder::GetMethod(METHOD__JIT_HELPERS__CONTAINSREFERENCES)->GetMemberDef())
     {
         _ASSERTE(ftn->HasMethodInstantiation());
@@ -7045,11 +6992,91 @@ bool getILIntrinsicImplementation(MethodDesc * ftn,
         methInfo->options = (CorInfoOptions)0;
         return true;
     }
-#endif
+#endif // FEATURE_SPAN_OF_T
 
     return false;
 }
 
+#ifdef FEATURE_SPAN_OF_T
+bool getILIntrinsicImplementationForUnsafe(MethodDesc * ftn,
+                                           CORINFO_METHOD_INFO * methInfo)
+{
+    STANDARD_VM_CONTRACT;
+
+    // Precondition: ftn is a method in mscorlib 
+    _ASSERTE(ftn->GetModule()->IsSystem());
+
+    mdMethodDef tk = ftn->GetMemberDef();
+
+    if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__SIZEOF)->GetMemberDef())
+    {
+        _ASSERTE(ftn->HasMethodInstantiation());
+        Instantiation inst = ftn->GetMethodInstantiation();
+
+        _ASSERTE(ftn->GetNumGenericMethodArgs() == 1);
+        mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
+
+        static const BYTE ilcode[] = { CEE_PREFIX1, (BYTE)CEE_SIZEOF, (BYTE)(tokGenericArg), (BYTE)(tokGenericArg >> 8), (BYTE)(tokGenericArg >> 16), (BYTE)(tokGenericArg >> 24),
+            CEE_RET };
+
+        methInfo->ILCode = const_cast<BYTE*>(ilcode);
+        methInfo->ILCodeSize = sizeof(ilcode);
+        methInfo->maxStack = 1;
+        methInfo->EHcount = 0;
+        methInfo->options = (CorInfoOptions)0;
+        return true;
+    }
+    else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_AS)->GetMemberDef())
+    {
+        // Return the argument that was passed in.
+        static const BYTE ilcode[] = { CEE_LDARG_0, CEE_RET };
+        methInfo->ILCode = const_cast<BYTE*>(ilcode);
+        methInfo->ILCodeSize = sizeof(ilcode);
+        methInfo->maxStack = 1;
+        methInfo->EHcount = 0;
+        methInfo->options = (CorInfoOptions)0;
+        return true;
+    }
+    else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ADD)->GetMemberDef())
+    {
+        mdToken tokGenericArg = FindGenericMethodArgTypeSpec(MscorlibBinder::GetModule()->GetMDImport());
+
+        static BYTE ilcode[] = { CEE_LDARG_1,
+            CEE_PREFIX1,(BYTE)CEE_SIZEOF,0,0,0,0,
+            CEE_CONV_I,
+            CEE_MUL,
+            CEE_LDARG_0,
+            CEE_ADD,
+            CEE_RET };
+
+        ilcode[3] = (BYTE)(tokGenericArg);
+        ilcode[4] = (BYTE)(tokGenericArg >> 8);
+        ilcode[5] = (BYTE)(tokGenericArg >> 16);
+        ilcode[6] = (BYTE)(tokGenericArg >> 24);
+
+        methInfo->ILCode = const_cast<BYTE*>(ilcode);
+        methInfo->ILCodeSize = sizeof(ilcode);
+        methInfo->maxStack = 2;
+        methInfo->EHcount = 0;
+        methInfo->options = (CorInfoOptions)0;
+        return true;
+    }
+    else if (tk == MscorlibBinder::GetMethod(METHOD__UNSAFE__BYREF_ARE_SAME)->GetMemberDef())
+    {
+        // Compare the two arguments
+        static const BYTE ilcode[] = { CEE_LDARG_0, CEE_LDARG_1, CEE_PREFIX1, (BYTE)CEE_CEQ, CEE_RET };
+        methInfo->ILCode = const_cast<BYTE*>(ilcode);
+        methInfo->ILCodeSize = sizeof(ilcode);
+        methInfo->maxStack = 2;
+        methInfo->EHcount = 0;
+        methInfo->options = (CorInfoOptions)0;
+        return true;
+    }
+
+    return false;
+}
+#endif // FEATURE_SPAN_OF_T
+
 bool getILIntrinsicImplementationForVolatile(MethodDesc * ftn,
                                              CORINFO_METHOD_INFO * methInfo)
 {
@@ -7230,6 +7257,12 @@ getMethodInfoHelper(
         {
             fILIntrinsic = getILIntrinsicImplementation(ftn, methInfo);
         }
+#ifdef FEATURE_SPAN_OF_T
+        else if (MscorlibBinder::IsClass(pMT, CLASS__UNSAFE))
+        {
+            fILIntrinsic = getILIntrinsicImplementationForUnsafe(ftn, methInfo);
+        }
+#endif
         else if (MscorlibBinder::IsClass(pMT, CLASS__INTERLOCKED))
         {
             fILIntrinsic = getILIntrinsicImplementationForInterlocked(ftn, methInfo);
index a8bcd81..7d75e59 100644 (file)
@@ -1347,14 +1347,19 @@ DEFINE_METHOD(JIT_HELPERS,          UNSAFE_CAST_TO_STACKPTR,UnsafeCastToStackPoi
 #ifdef FEATURE_SPAN_OF_T
 DEFINE_METHOD(JIT_HELPERS,          GET_BYREF,              GetByRef, NoSig)
 DEFINE_METHOD(JIT_HELPERS,          SET_BYREF,              SetByRef, NoSig)
-DEFINE_METHOD(JIT_HELPERS,          ADD_BYREF,              AddByRef, NoSig)
-DEFINE_METHOD(JIT_HELPERS,          BYREF_EQUALS,           ByRefEquals, NoSig)
 DEFINE_METHOD(JIT_HELPERS,          BYREF_LESSTHAN,         ByRefLessThan, NoSig)
 DEFINE_METHOD(JIT_HELPERS,          GET_ARRAY_DATA,         GetArrayData, NoSig)
-DEFINE_METHOD(JIT_HELPERS,          SIZEOF,                 SizeOf, NoSig)
 DEFINE_METHOD(JIT_HELPERS,          CONTAINSREFERENCES,     ContainsReferences, NoSig)
 #endif
 
+#ifdef FEATURE_SPAN_OF_T
+DEFINE_CLASS(UNSAFE,                CompilerServices,       Unsafe)
+DEFINE_METHOD(UNSAFE,               SIZEOF,                 SizeOf, NoSig)
+DEFINE_METHOD(UNSAFE,               BYREF_AS,               As, NoSig)
+DEFINE_METHOD(UNSAFE,               BYREF_ADD,              Add, NoSig)
+DEFINE_METHOD(UNSAFE,               BYREF_ARE_SAME,         AreSame, NoSig)
+#endif
+
 DEFINE_CLASS(INTERLOCKED,           Threading,              Interlocked)
 DEFINE_METHOD(INTERLOCKED,          COMPARE_EXCHANGE_T,     CompareExchange, GM_RefT_T_T_RetT)
 DEFINE_METHOD(INTERLOCKED,          COMPARE_EXCHANGE_OBJECT,CompareExchange, SM_RefObject_Object_Object_RetObject)