Fixup Span<T> implementation to be more similar to the corefx one (dotnet/coreclr...
authorJan Kotas <jkotas@microsoft.com>
Sat, 21 Jan 2017 01:13:50 +0000 (17:13 -0800)
committerGitHub <noreply@github.com>
Sat, 21 Jan 2017 01:13:50 +0000 (17:13 -0800)
- Reorder methods, adjust comments and formatting to make it easier to see the diff with corefx
- Delete extra implicit conversion operator

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

src/coreclr/src/mscorlib/model.xml
src/coreclr/src/mscorlib/src/System/ReadOnlySpan.cs
src/coreclr/src/mscorlib/src/System/Span.cs

index f95dc80..ad00171 100644 (file)
       <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;" />
       <Member Name="op_Equality(System.ReadOnlySpan&lt;T&gt;,System.ReadOnlySpan&lt;T&gt;)" />
index 83b2123..c7125eb 100644 (file)
@@ -2,18 +2,17 @@
 // 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.Collections.Generic;
-using System.ComponentModel;
 using System.Diagnostics;
 using System.Runtime.CompilerServices;
+using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
 
 #pragma warning disable 0809  //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
 
 namespace System
 {
     /// <summary>
-    /// ReadOnlySpan represents contiguous read-only region of arbitrary memory, with performance
-    /// characteristics on par with T[]. Unlike arrays, it can point to either managed
+    /// ReadOnlySpan represents a contiguous region of arbitrary memory. 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 struct ReadOnlySpan<T>
@@ -24,11 +23,12 @@ namespace System
         private readonly int _length;
 
         /// <summary>
-        /// Creates a new span over the entirety of the target array.
+        /// Creates a new read-only span over the entirety of the target array.
         /// </summary>
         /// <param name="array">The target array.</param>
         /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
         /// reference (Nothing in Visual Basic).</exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public ReadOnlySpan(T[] array)
         {
             if (array == null)
@@ -39,16 +39,17 @@ namespace System
         }
 
         /// <summary>
-        /// Creates a new span over the portion of the target array beginning
+        /// Creates a new read-only span over the portion of the target array beginning
         /// at 'start' index and covering the remainder of the array.
         /// </summary>
         /// <param name="array">The target array.</param>
-        /// <param name="start">The index at which to begin the span.</param>
+        /// <param name="start">The index at which to begin the read-only span.</param>
         /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
         /// reference (Nothing in Visual Basic).</exception>
         /// <exception cref="System.ArgumentOutOfRangeException">
-        /// Thrown when the specified <paramref name="start"/> is not in the range (&lt;0 or &gt;&eq;Length).
+        /// Thrown when the specified <paramref name="start"/> is not in the range (&lt;0 or &gt;=Length).
         /// </exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public ReadOnlySpan(T[] array, int start)
         {
             if (array == null)
@@ -61,17 +62,18 @@ namespace System
         }
 
         /// <summary>
-        /// Creates a new span over the portion of the target array beginning
+        /// Creates a new read-only span over the portion of the target array beginning
         /// at 'start' index and ending at 'end' index (exclusive).
         /// </summary>
         /// <param name="array">The target array.</param>
-        /// <param name="start">The index at which to begin the span.</param>
-        /// <param name="length">The number of items in the span.</param>
+        /// <param name="start">The index at which to begin the read-only span.</param>
+        /// <param name="length">The number of items in the read-only span.</param>
         /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
         /// reference (Nothing in Visual Basic).</exception>
         /// <exception cref="System.ArgumentOutOfRangeException">
-        /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;&eq;Length).
+        /// Thrown when the specified <paramref name="start"/> or end index is not in the range (&lt;0 or &gt;=Length).
         /// </exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public ReadOnlySpan(T[] array, int start, int length)
         {
             if (array == null)
@@ -84,12 +86,12 @@ namespace System
         }
 
         /// <summary>
-        /// Creates a new span over the target unmanaged buffer.  Clearly this
+        /// Creates a new read-only span over the target unmanaged buffer.  Clearly this
         /// is quite dangerous, because we are creating arbitrarily typed T's
         /// out of a void*-typed block of memory.  And the length is not checked.
         /// But if this creation is correct, then all subsequent uses are correct.
         /// </summary>
-        /// <param name="ptr">An unmanaged pointer to memory.</param>
+        /// <param name="pointer">An unmanaged pointer to memory.</param>
         /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
         /// <exception cref="System.ArgumentException">
         /// Thrown when <typeparamref name="T"/> is reference type or contains pointers and hence cannot be stored in unmanaged memory.
@@ -98,6 +100,7 @@ namespace System
         /// Thrown when the specified <paramref name="length"/> is negative.
         /// </exception>
         [CLSCompliant(false)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public unsafe ReadOnlySpan(void* pointer, int length)
         {
             if (JitHelpers.ContainsReferences<T>())
@@ -110,10 +113,36 @@ namespace System
         }
 
         /// <summary>
-        /// An internal helper for creating spans.
+        /// Create a new read-only span over a portion of a regular managed object. This can be useful
+        /// if part of a managed object represents a "fixed array." This is dangerous because
+        /// "length" is not checked, nor is the fact that "rawPointer" actually lies within the object.
         /// </summary>
+        /// <param name="obj">The managed object that contains the data to span over.</param>
+        /// <param name="objectData">A reference to data within that object.</param>
+        /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
+        /// <exception cref="System.ArgumentNullException">
+        /// Thrown when the specified object is null.
+        /// </exception>
+        /// <exception cref="System.ArgumentOutOfRangeException">
+        /// Thrown when the specified <paramref name="length"/> is negative.
+        /// </exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public static ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length)
+        {
+            if (obj == null)
+                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);
+            if (length < 0)
+                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
+
+            return new ReadOnlySpan<T>(ref objectData, length);
+        }
+
+        // Constructor for internal use only.
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal ReadOnlySpan(ref T ptr, int length)
         {
+            Debug.Assert(length >= 0);
+
             _pointer = new ByReference<T>(ref ptr);
             _length = length;
         }
@@ -122,151 +151,135 @@ namespace System
         /// 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>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public ref T DangerousGetPinnableReference()
         {
             return ref _pointer.Value;
         }
 
         /// <summary>
-        /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
-        /// <exception cref="System.NotSupportedException">
-        /// Always thrown by this method.
-        /// </exception>
+        /// The number of items in the read-only span.
         /// </summary>
-        [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override bool Equals(object obj)
-        {
-            ThrowHelper.ThrowNotSupportedException_CannotCallEqualsOnSpan();
-            // Prevent compiler error CS0161: 'Span<T>.Equals(object)': not all code paths return a value
-            return default(bool);
-        }
+        public int Length => _length;
 
         /// <summary>
-        /// This method is not supported as spans cannot be boxed.
-        /// <exception cref="System.NotSupportedException">
-        /// Always thrown by this method.
-        /// </exception>
+        /// Returns true if Length is 0.
         /// </summary>
-        [Obsolete("GetHashCode() on Span will always throw an exception.")]
-        [EditorBrowsable(EditorBrowsableState.Never)]
-        public override int GetHashCode()
-        {
-            ThrowHelper.ThrowNotSupportedException_CannotCallGetHashCodeOnSpan();
-            // Prevent compiler error CS0161: 'Span<T>.GetHashCode()': not all code paths return a value
-            return default(int);
-        }
+        public bool IsEmpty => _length == 0;
 
         /// <summary>
-        /// Create a new read-only span over a portion of a regular managed object. This can be useful
-        /// if part of a managed object represents a "fixed array." This is dangerous because
-        /// "length" is not checked, nor is the fact that "rawPointer" actually lies within the object.
+        /// Returns the specified element of the read-only span.
         /// </summary>
-        /// <param name="obj">The managed object that contains the data to span over.</param>
-        /// <param name="objectData">A reference to data within that object.</param>
-        /// <param name="length">The number of <typeparamref name="T"/> elements the memory contains.</param>
-        /// <exception cref="System.ArgumentNullException">
-        /// Thrown when the specified object is null.
-        /// </exception>
-        /// <exception cref="System.ArgumentOutOfRangeException">
-        /// Thrown when the specified <paramref name="length"/> is negative.
+        /// <param name="index"></param>
+        /// <returns></returns>
+        /// <exception cref="System.IndexOutOfRangeException">
+        /// Thrown when index less than 0 or index greater than or equal to Length
         /// </exception>
-        public static ReadOnlySpan<T> DangerousCreate(object obj, ref T objectData, int length)
+        public T this[int index]
         {
-            if (obj == null)
-                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.obj);
-            if (length < 0)
-                ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length);
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
+            get
+            {
+                if ((uint)index >= (uint)_length)
+                    ThrowHelper.ThrowIndexOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref objectData, length);
+                return Unsafe.Add(ref _pointer.Value, index);
+            }
         }
 
         /// <summary>
-        /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
+        /// Copies the contents of this read-only span into destination span. If the source
+        /// and destinations overlap, this method behaves as if the original values in
+        /// a temporary location before the destination is overwritten.
+        ///
+        /// <param name="destination">The span to copy items into.</param>
+        /// <exception cref="System.ArgumentException">
+        /// Thrown when the destination Span is shorter than the source Span.
+        /// </exception>
         /// </summary>
-        public static implicit operator ReadOnlySpan<T>(Span<T> slice)
+        public void CopyTo(Span<T> destination)
         {
-            return new ReadOnlySpan<T>(ref slice.DangerousGetPinnableReference(), slice.Length);
+            if (!TryCopyTo(destination))
+                ThrowHelper.ThrowArgumentException_DestinationTooShort();
         }
 
-        /// <summary>
-        /// Defines an implicit conversion of an array to a <see cref="ReadOnlySpan{T}"/>
+        /// Copies the contents of this read-only span into destination span. If the source
+        /// and destinations overlap, this method behaves as if the original values in
+        /// a temporary location before the destination is overwritten.
         /// </summary>
-        public static implicit operator ReadOnlySpan<T>(T[] array)
+        /// <returns>If the destination span is shorter than the source span, this method
+        /// return false and no data is written to the destination.</returns>
+        /// <param name="destination">The span to copy items into.</param>
+        public bool TryCopyTo(Span<T> destination)
         {
-            return new ReadOnlySpan<T>(array);
+            if ((uint)_length > (uint)destination.Length)
+                return false;
+
+            SpanHelper.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref _pointer.Value, _length);
+            return true;
         }
 
         /// <summary>
-        /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlySpan{T}"/>
+        /// Returns true if left and right point at the same memory and have the same length.  Note that
+        /// this does *not* check to see if the *contents* are equal.
         /// </summary>
-        public static implicit operator ReadOnlySpan<T>(ArraySegment<T> arraySegment)
+        public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right)
         {
-            return new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+            return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
         }
 
         /// <summary>
-        /// Gets the number of elements contained in the <see cref="ReadOnlySpan{T}"/>
+        /// Returns false if left and right point at the same memory and have the same length.  Note that
+        /// this does *not* check to see if the *contents* are equal.
         /// </summary>
-        public int Length
-        {
-            get { return _length; }
-        }
+        public static bool operator !=(ReadOnlySpan<T> left, ReadOnlySpan<T> right) => !(left == right);
 
         /// <summary>
-        /// Returns an empty <see cref="ReadOnlySpan{T}"/>
+        /// This method is not supported as spans cannot be boxed. To compare two spans, use operator==.
+        /// <exception cref="System.NotSupportedException">
+        /// Always thrown by this method.
+        /// </exception>
         /// </summary>
-        public static ReadOnlySpan<T> Empty
+        [Obsolete("Equals() on Span will always throw an exception. Use == instead.")]
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override bool Equals(object obj)
         {
-            get { return default(ReadOnlySpan<T>); }
+            ThrowHelper.ThrowNotSupportedException_CannotCallEqualsOnSpan();
+            // Prevent compiler error CS0161: 'Span<T>.Equals(object)': not all code paths return a value
+            return default(bool);
         }
 
         /// <summary>
-        /// Returns whether the <see cref="ReadOnlySpan{T}"/> is empty.
+        /// This method is not supported as spans cannot be boxed.
+        /// <exception cref="System.NotSupportedException">
+        /// Always thrown by this method.
+        /// </exception>
         /// </summary>
-        public bool IsEmpty
+        [Obsolete("GetHashCode() on Span will always throw an exception.")]
+        [EditorBrowsable(EditorBrowsableState.Never)]
+        public override int GetHashCode()
         {
-            get { return _length == 0; }
+            ThrowHelper.ThrowNotSupportedException_CannotCallGetHashCodeOnSpan();
+            // Prevent compiler error CS0161: 'Span<T>.GetHashCode()': not all code paths return a value
+            return default(int);
         }
 
         /// <summary>
-        /// Fetches the element at the specified index.
+        /// Defines an implicit conversion of an array to a <see cref="ReadOnlySpan{T}"/>
         /// </summary>
-        /// <exception cref="System.IndexOutOfRangeException">
-        /// Thrown when the specified <paramref name="index"/> is not in range (&lt;0 or &gt;&eq;Length).
-        /// </exception>
-        public T this[int index]
-        {
-            get
-            {
-                if ((uint)index >= (uint)_length)
-                    ThrowHelper.ThrowIndexOutOfRangeException();
-
-                return Unsafe.Add(ref DangerousGetPinnableReference(), index);
-            }
-        }
+        public static implicit operator ReadOnlySpan<T>(T[] array) => new ReadOnlySpan<T>(array);
 
         /// <summary>
-        /// Copies the contents of this span into a new array.  This heap
-        /// allocates, so should generally be avoided, however is sometimes
-        /// necessary to bridge the gap with APIs written in terms of arrays.
+        /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="ReadOnlySpan{T}"/>
         /// </summary>
-        public T[] ToArray()
-        {
-            if (_length == 0)
-                return Array.Empty<T>();
-
-            var destination = new T[_length];
-            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
-            return destination;
-        }
+        public static implicit operator ReadOnlySpan<T>(ArraySegment<T> arraySegment) => new ReadOnlySpan<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
 
         /// <summary>
-        /// Forms a slice out of the given span, beginning at 'start'.
+        /// Forms a slice out of the given read-only span, beginning at 'start'.
         /// </summary>
         /// <param name="start">The index at which to begin this slice.</param>
         /// <exception cref="System.ArgumentOutOfRangeException">
-        /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;length).
+        /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
         /// </exception>
         [MethodImpl(MethodImplOptions.NoOptimization)] // TODO-SPAN: Workaround for https://github.com/dotnet/coreclr/issues/7894
         public ReadOnlySpan<T> Slice(int start)
@@ -274,16 +287,16 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
         }
 
         /// <summary>
-        /// Forms a slice out of the given span, beginning at 'start', of given length
+        /// Forms a slice out of the given read-only span, beginning at 'start', of given length
         /// </summary>
         /// <param name="start">The index at which to begin this slice.</param>
-        /// <param name="end">The index at which to end this slice (exclusive).</param>
+        /// <param name="length">The desired length for the slice (exclusive).</param>
         /// <exception cref="System.ArgumentOutOfRangeException">
-        /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;&eq;Length).
+        /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
         /// </exception>
         [MethodImpl(MethodImplOptions.NoOptimization)] // TODO-SPAN: Workaround for https://github.com/dotnet/coreclr/issues/7894
         public ReadOnlySpan<T> Slice(int start, int length)
@@ -291,53 +304,28 @@ namespace System
             if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new ReadOnlySpan<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
-        }
-
-        /// <summary>
-        /// Copies the contents of this read-only span into destination span. If the source
-        /// and destinations overlap, this method behaves as if the original values in
-        /// a temporary location before the destination is overwritten.
-        ///
-        /// <param name="destination">The span to copy items into.</param>
-        /// <exception cref="System.ArgumentException">
-        /// Thrown when the destination Span is shorter than the source Span.
-        /// </exception>
-        /// </summary>
-        public void CopyTo(Span<T> destination)
-        {
-            if (!TryCopyTo(destination))
-                ThrowHelper.ThrowArgumentException_DestinationTooShort();
+            return new ReadOnlySpan<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
         }
 
         /// <summary>
-        /// Copies the contents of this span into destination span. The destination
-        /// must be at least as big as the source, and may be bigger.
+        /// Copies the contents of this read-only span into a new array.  This heap
+        /// allocates, so should generally be avoided, however it is sometimes
+        /// necessary to bridge the gap with APIs written in terms of arrays.
         /// </summary>
-        /// <param name="destination">The span to copy items into.</param>
-        public bool TryCopyTo(Span<T> destination)
+        public T[] ToArray()
         {
-            if ((uint)_length > (uint)destination.Length)
-                return false;
-
-            SpanHelper.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length);
-            return true;
-        }
+            if (_length == 0)
+                return Array.Empty<T>();
 
-        /// <summary>
-        /// Returns true if left and right point at the same memory and have the same length.  Note that
-        /// this does *not* check to see if the *contents* are equal.
-        /// </summary>
-        public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right)
-        {
-            return left._length == right._length && Unsafe.AreSame<T>(ref left.DangerousGetPinnableReference(), ref right.DangerousGetPinnableReference());
+            var destination = new T[_length];
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref _pointer.Value, _length);
+            return destination;
         }
 
         /// <summary>
-        /// Returns false if left and right point at the same memory and have the same length.  Note that
-        /// this does *not* check to see if the *contents* are equal.
+        /// Returns a 0-length read-only span whose base is the null pointer.
         /// </summary>
-        public static bool operator !=(ReadOnlySpan<T> left, ReadOnlySpan<T> right) => !(left == right);
+        public static ReadOnlySpan<T> Empty => default(ReadOnlySpan<T>);
     }
 
     public static class ReadOnlySpanExtensions
index d7f8dc5..19e21c0 100644 (file)
@@ -2,18 +2,17 @@
 // 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.Collections.Generic;
-using System.ComponentModel;
 using System.Diagnostics;
 using System.Runtime.CompilerServices;
+using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
+using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
 
 #pragma warning disable 0809  //warning CS0809: Obsolete member 'Span<T>.Equals(object)' overrides non-obsolete member 'object.Equals(object)'
 
 namespace System
 {
     /// <summary>
-    /// Span represents contiguous region of arbitrary memory, with performance
-    /// characteristics on par with T[]. Unlike arrays, it can point to either managed
+    /// Span represents a contiguous region of arbitrary memory. 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 struct Span<T>
@@ -30,14 +29,13 @@ namespace System
         /// <exception cref="System.ArgumentNullException">Thrown when <paramref name="array"/> is a null
         /// reference (Nothing in Visual Basic).</exception>
         /// <exception cref="System.ArrayTypeMismatchException">Thrown when <paramref name="array"/> is covariant and array's type is not exactly T[].</exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public Span(T[] array)
         {
             if (array == null)
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-            if (default(T) == null) { // Arrays of valuetypes are never covariant
-                if (array.GetType() != typeof(T[]))
-                    ThrowHelper.ThrowArrayTypeMismatchException();
-            }
+            if (default(T) == null && array.GetType() != typeof(T[]))
+                ThrowHelper.ThrowArrayTypeMismatchException();
 
             _pointer = new ByReference<T>(ref JitHelpers.GetArrayData(array));
             _length = array.Length;
@@ -55,14 +53,13 @@ namespace System
         /// <exception cref="System.ArgumentOutOfRangeException">
         /// Thrown when the specified <paramref name="start"/> is not in the range (&lt;0 or &gt;=Length).
         /// </exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public Span(T[] array, int start)
         {
             if (array == null)
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-            if (default(T) == null) { // Arrays of valuetypes are never covariant
-                if (array.GetType() != typeof(T[]))
-                    ThrowHelper.ThrowArrayTypeMismatchException();
-            }
+            if (default(T) == null && array.GetType() != typeof(T[]))
+                ThrowHelper.ThrowArrayTypeMismatchException();
             if ((uint)start > (uint)array.Length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
@@ -87,10 +84,8 @@ namespace System
         {
             if (array == null)
                 ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
-            if (default(T) == null) { // Arrays of valuetypes are never covariant
-                if (array.GetType() != typeof(T[]))
-                    ThrowHelper.ThrowArrayTypeMismatchException();
-            }
+            if (default(T) == null && array.GetType() != typeof(T[]))
+                ThrowHelper.ThrowArrayTypeMismatchException();
             if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
@@ -138,6 +133,7 @@ namespace System
         /// <exception cref="System.ArgumentOutOfRangeException">
         /// Thrown when the specified <paramref name="length"/> is negative.
         /// </exception>
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static Span<T> DangerousCreate(object obj, ref T objectData, int length)
         {
             if (obj == null)
@@ -147,13 +143,13 @@ namespace System
 
             return new Span<T>(ref objectData, length);
         }
-        
 
-        /// <summary>
-        /// An internal helper for creating spans.
-        /// </summary>
+        // Constructor for internal use only.
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         internal Span(ref T ptr, int length)
         {
+            Debug.Assert(length >= 0);
+
             _pointer = new ByReference<T>(ref ptr);
             _length = length;
         }
@@ -168,40 +164,69 @@ namespace System
         }
 
         /// <summary>
-        /// Gets the number of elements contained in the <see cref="Span{T}"/>
+        /// The number of items in the span.
         /// </summary>
         public int Length => _length;
 
         /// <summary>
-        /// Returns whether the <see cref="Span{T}"/> is empty.
+        /// Returns true if Length is 0.
         /// </summary>
         public bool IsEmpty => _length == 0;
 
         /// <summary>
-        /// Fetches the element at the specified index.
+        /// Returns a reference to specified element of the Span.
         /// </summary>
+        /// <param name="index"></param>
+        /// <returns></returns>
         /// <exception cref="System.IndexOutOfRangeException">
-        /// Thrown when the specified <paramref name="index"/> is not in range (&lt;0 or &gt;&eq;Length).
+        /// Thrown when index less than 0 or index greater than or equal to Length
         /// </exception>
+
+        // TODO: https://github.com/dotnet/corefx/issues/13681
+        //   Until we get over the hurdle of C# 7 tooling, this indexer will return "T" and have a setter rather than a "ref T". (The doc comments
+        //   continue to reflect the original intent of returning "ref T")
         public T this[int index]
         {
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
             get
             {
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                return Unsafe.Add(ref DangerousGetPinnableReference(), index);
+                return Unsafe.Add(ref _pointer.Value, index);
             }
+            [MethodImpl(MethodImplOptions.AggressiveInlining)]
             set
             {
                 if ((uint)index >= (uint)_length)
                     ThrowHelper.ThrowIndexOutOfRangeException();
 
-                Unsafe.Add(ref DangerousGetPinnableReference(), index) = value;
+                Unsafe.Add(ref _pointer.Value, index) = value;
             }
         }
 
         /// <summary>
+        /// Returns a reference to specified element of the Span.
+        /// </summary>
+        /// <param name="index"></param>
+        /// <returns></returns>
+        /// <exception cref="System.IndexOutOfRangeException">
+        /// Thrown when index less than 0 or index greater than or equal to Length
+        /// </exception>
+
+        // TODO: https://github.com/dotnet/corefx/issues/13681
+        //   Until we get over the hurdle of C# 7 tooling, this temporary method will simulate the intended "ref T" indexer for those
+        //   who need bypass the workaround for performance.
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        public ref T GetItem(int index)
+        {
+            if ((uint)index >= ((uint)_length))
+                ThrowHelper.ThrowIndexOutOfRangeException();
+
+            return ref Unsafe.Add(ref _pointer.Value, index);
+        }
+
+        /// <summary>
         /// Copies the contents of this span into destination span. If the source
         /// and destinations overlap, this method behaves as if the original values in
         /// a temporary location before the destination is overwritten.
@@ -229,7 +254,7 @@ namespace System
             if ((uint)_length > (uint)destination.Length)
                 return false;
 
-            SpanHelper.CopyTo<T>(ref destination.DangerousGetPinnableReference(), ref DangerousGetPinnableReference(), _length);
+            SpanHelper.CopyTo<T>(ref destination._pointer.Value, ref _pointer.Value, _length);
             return true;
         }
 
@@ -239,7 +264,7 @@ namespace System
         /// </summary>
         public static bool operator ==(Span<T> left, Span<T> right)
         {
-            return left._length == right._length && Unsafe.AreSame<T>(ref left.DangerousGetPinnableReference(), ref right.DangerousGetPinnableReference());
+            return left._length == right._length && Unsafe.AreSame<T>(ref left._pointer.Value, ref right._pointer.Value);
         }
 
         /// <summary>
@@ -286,19 +311,19 @@ namespace System
         /// <summary>
         /// Defines an implicit conversion of a <see cref="ArraySegment{T}"/> to a <see cref="Span{T}"/>
         /// </summary>
-        public static implicit operator Span<T>(ArraySegment<T> arraySegment) =>  new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
+        public static implicit operator Span<T>(ArraySegment<T> arraySegment) => new Span<T>(arraySegment.Array, arraySegment.Offset, arraySegment.Count);
 
         /// <summary>
         /// Defines an implicit conversion of a <see cref="Span{T}"/> to a <see cref="ReadOnlySpan{T}"/>
         /// </summary>
-        public static implicit operator ReadOnlySpan<T>(Span<T> span) => new ReadOnlySpan<T>(ref span.DangerousGetPinnableReference(), span._length);
+        public static implicit operator ReadOnlySpan<T>(Span<T> span) => new ReadOnlySpan<T>(ref span._pointer.Value, span._length);
 
         /// <summary>
         /// Forms a slice out of the given span, beginning at 'start'.
         /// </summary>
         /// <param name="start">The index at which to begin this slice.</param>
         /// <exception cref="System.ArgumentOutOfRangeException">
-        /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;Length).
+        /// Thrown when the specified <paramref name="start"/> index is not in range (&lt;0 or &gt;=Length).
         /// </exception>
         [MethodImpl(MethodImplOptions.NoOptimization)] // TODO-SPAN: Workaround for https://github.com/dotnet/coreclr/issues/7894
         public Span<T> Slice(int start)
@@ -306,7 +331,7 @@ namespace System
             if ((uint)start > (uint)_length)
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new Span<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), _length - start);
+            return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), _length - start);
         }
 
         /// <summary>
@@ -315,7 +340,7 @@ namespace System
         /// <param name="start">The index at which to begin this slice.</param>
         /// <param name="length">The desired length for the slice (exclusive).</param>
         /// <exception cref="System.ArgumentOutOfRangeException">
-        /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;&eq;Length).
+        /// Thrown when the specified <paramref name="start"/> or end index is not in range (&lt;0 or &gt;=Length).
         /// </exception>
         [MethodImpl(MethodImplOptions.NoOptimization)] // TODO-SPAN: Workaround for https://github.com/dotnet/coreclr/issues/7894
         public Span<T> Slice(int start, int length)
@@ -323,7 +348,7 @@ namespace System
             if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
                 ThrowHelper.ThrowArgumentOutOfRangeException();
 
-            return new Span<T>(ref Unsafe.Add(ref DangerousGetPinnableReference(), start), length);
+            return new Span<T>(ref Unsafe.Add(ref _pointer.Value, start), length);
         }
 
         /// <summary>
@@ -337,7 +362,7 @@ namespace System
                 return Array.Empty<T>();
 
             var destination = new T[_length];
-            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref DangerousGetPinnableReference(), _length);
+            SpanHelper.CopyTo<T>(ref JitHelpers.GetArrayData(destination), ref _pointer.Value, _length);
             return destination;
         }