Preserve pinned flag in {ReadOnly}Memory<T>.Slice (dotnet/corefx#29246) (#17712)
authordotnet bot <dotnet-bot@dotnetfoundation.org>
Sat, 21 Apr 2018 00:56:35 +0000 (17:56 -0700)
committerAhson Khan <ahkha@microsoft.com>
Sat, 21 Apr 2018 00:56:35 +0000 (17:56 -0700)
* Preserve pinned flag in {ReadOnly}Memory<T>.Slice

* Address PR feedback.

Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
src/mscorlib/shared/System/Memory.cs
src/mscorlib/shared/System/ReadOnlyMemory.cs

index c06b1b4..0abe363 100644 (file)
@@ -225,13 +225,16 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public Memory<T> Slice(int start)
         {
-            int actualLength = _length & RemoveFlagsBitMask;
+            // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not.
+            int capturedLength = _length;
+            int actualLength = capturedLength & RemoveFlagsBitMask;
             if ((uint)start > (uint)actualLength)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
             }
 
-            return new Memory<T>(_object, _index + start, actualLength - start);
+            // It is expected for (capturedLength - start) to be negative if the memory is already pre-pinned.
+            return new Memory<T>(_object, _index + start, capturedLength - start);
         }
 
         /// <summary>
@@ -245,13 +248,16 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public Memory<T> Slice(int start, int length)
         {
-            int actualLength = _length & RemoveFlagsBitMask;
+            // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not.
+            int capturedLength = _length;
+            int actualLength = capturedLength & RemoveFlagsBitMask;
             if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start))
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException();
             }
 
-            return new Memory<T>(_object, _index + start, length);
+            // Set the high-bit to match the this._length high bit (1 for pre-pinned, 0 for unpinned).
+            return new Memory<T>(_object, _index + start, length | (capturedLength & ~RemoveFlagsBitMask));
         }
 
         /// <summary>
index 91a3522..78f328a 100644 (file)
@@ -147,13 +147,16 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public ReadOnlyMemory<T> Slice(int start)
         {
-            int actualLength = _length & RemoveFlagsBitMask;
+            // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not.
+            int capturedLength = _length;
+            int actualLength = capturedLength & RemoveFlagsBitMask;
             if ((uint)start > (uint)actualLength)
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
             }
 
-            return new ReadOnlyMemory<T>(_object, _index + start, actualLength - start);
+            // It is expected for (capturedLength - start) to be negative if the memory is already pre-pinned.
+            return new ReadOnlyMemory<T>(_object, _index + start, capturedLength - start);
         }
 
         /// <summary>
@@ -167,13 +170,16 @@ namespace System
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public ReadOnlyMemory<T> Slice(int start, int length)
         {
+            // Used to maintain the high-bit which indicates whether the Memory has been pre-pinned or not.
+            int capturedLength = _length;
             int actualLength = _length & RemoveFlagsBitMask;
             if ((uint)start > (uint)actualLength || (uint)length > (uint)(actualLength - start))
             {
                 ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.start);
             }
 
-            return new ReadOnlyMemory<T>(_object, _index + start, length);
+            // Set the high-bit to match the this._length high bit (1 for pre-pinned, 0 for unpinned).
+            return new ReadOnlyMemory<T>(_object, _index + start, length | (capturedLength & ~RemoveFlagsBitMask));
         }
 
         /// <summary>