Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/corefx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordotnet bot <dotnet-bot@dotnetfoundation.org>2018-03-29 06:22:38 +0300
committerAhson Khan <ahkha@microsoft.com>2018-03-29 06:22:38 +0300
commitbb5c46859048bfcefca281d7c303540c1217da41 (patch)
tree0364eacd3d965776f59fede61ceb601e353a8ba5
parent52bdd078870fb3b10ed050b0bc40391e90c9c6b0 (diff)
Mirror changes from dotnet/coreclr (#28534)
* Adding Memory.Pin() to eventually replace Memory.Retain(bool) (#17269) * Adding Memory.Pin() to eventually replace Memory.Retain(bool) * Fix copy/paste error and return default for when object is null. * Fix XML comments. Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com> * Add Memory.Pin to the ref and add tests. * Add Pin tests * Update calls to Retain(true) to now call Pin() * Remove extra space in tests. * Add Pin to the ApiCompatBaseline for uapaot.
-rw-r--r--src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs2
-rw-r--r--src/Common/src/CoreLib/System/Memory.cs44
-rw-r--r--src/Common/src/CoreLib/System/ReadOnlyMemory.cs38
-rw-r--r--src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs2
-rw-r--r--src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs2
-rw-r--r--src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs2
-rw-r--r--src/System.Memory/ref/System.Memory.cs2
-rw-r--r--src/System.Memory/tests/Memory/Pin.cs133
-rw-r--r--src/System.Memory/tests/Memory/Retain.cs48
-rw-r--r--src/System.Memory/tests/Memory/Strings.cs9
-rw-r--r--src/System.Memory/tests/MemoryMarshal/AsMemory.cs23
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Pin.cs133
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Retain.cs30
-rw-r--r--src/System.Memory/tests/ReadOnlyMemory/Strings.cs11
-rw-r--r--src/System.Memory/tests/System.Memory.Tests.csproj2
-rw-r--r--src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs2
-rw-r--r--src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs8
-rw-r--r--src/System.Runtime/ref/System.Runtime.cs2
-rw-r--r--src/System.Runtime/src/ApiCompatBaseline.uapaot.txt4
-rw-r--r--src/shims/ApiCompatBaseline.uapaot.netstandard20.txt4
20 files changed, 424 insertions, 77 deletions
diff --git a/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs b/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs
index 82274b131f..62ace0918d 100644
--- a/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs
+++ b/src/Common/src/CoreLib/System/IO/FileStreamCompletionSource.Win32.cs
@@ -246,7 +246,7 @@ namespace System.IO
internal MemoryFileStreamCompletionSource(FileStream stream, int numBufferedBytes, ReadOnlyMemory<byte> memory) :
base(stream, numBufferedBytes, bytes: null) // this type handles the pinning, so null is passed for bytes
{
- _handle = memory.Retain(pin: true);
+ _handle = memory.Pin();
}
internal override void ReleaseNativeResource()
diff --git a/src/Common/src/CoreLib/System/Memory.cs b/src/Common/src/CoreLib/System/Memory.cs
index 508ebcb3ee..bb2b1557a9 100644
--- a/src/Common/src/CoreLib/System/Memory.cs
+++ b/src/Common/src/CoreLib/System/Memory.cs
@@ -270,9 +270,49 @@ namespace System
public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
/// <summary>
- /// Returns a handle for the array.
- /// <param name="pin">If pin is true, the GC will not move the array and hence its address can be taken</param>
+ /// Creates a handle for the memory.
+ /// The GC will not move the array until the returned <see cref="MemoryHandle"/>
+ /// is disposed, enabling taking and using the memory's address.
/// </summary>
+ public unsafe MemoryHandle Pin()
+ {
+ if (_index < 0)
+ {
+ return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
+ }
+ else if (typeof(T) == typeof(char) && _object is string s)
+ {
+ // This case can only happen if a ReadOnlyMemory<char> was created around a string
+ // and then that was cast to a Memory<char> using unsafe / marshaling code. This needs
+ // to work, however, so that code that uses a single Memory<char> field to store either
+ // a readable ReadOnlyMemory<char> or a writable Memory<char> can still be pinned and
+ // used for interop purposes.
+ GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ else if (_object is T[] array)
+ {
+ var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ return default;
+ }
+
+ /// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
+ /// <param name="pin">
+ /// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
+ /// is disposed, enabling taking and using the memory's address.
+ /// </param>
public unsafe MemoryHandle Retain(bool pin = false)
{
MemoryHandle memoryHandle = default;
diff --git a/src/Common/src/CoreLib/System/ReadOnlyMemory.cs b/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
index 5f3f0e1980..dca7db3dfd 100644
--- a/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
+++ b/src/Common/src/CoreLib/System/ReadOnlyMemory.cs
@@ -226,10 +226,44 @@ namespace System
/// <param name="destination">The span to copy items into.</param>
public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
- /// <summary>Creates a handle for the memory.</summary>
+ /// <summary>
+ /// Creates a handle for the memory.
+ /// The GC will not move the array until the returned <see cref="MemoryHandle"/>
+ /// is disposed, enabling taking and using the memory's address.
+ /// </summary>
+ public unsafe MemoryHandle Pin()
+ {
+ if (_index < 0)
+ {
+ return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
+ }
+ else if (typeof(T) == typeof(char) && _object is string s)
+ {
+ GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ else if (_object is T[] array)
+ {
+ var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
+#if FEATURE_PORTABLE_SPAN
+ void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
+#else
+ void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
+#endif // FEATURE_PORTABLE_SPAN
+ return new MemoryHandle(null, pointer, handle);
+ }
+ return default;
+ }
+
+ /// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
/// <param name="pin">
/// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
- /// is disposed, enabling the memory's address can be taken and used.
+ /// is disposed, enabling taking and using the memory's address.
/// </param>
public unsafe MemoryHandle Retain(bool pin = false)
{
diff --git a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
index 637aae916d..861ee6ca9b 100644
--- a/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
+++ b/src/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs
@@ -232,7 +232,7 @@ internal static partial class Interop
int retVal;
unsafe
{
- using (MemoryHandle handle = input.Retain(pin: true))
+ using (MemoryHandle handle = input.Pin())
{
retVal = Ssl.SslWrite(context, (byte*)handle.Pointer, input.Length);
}
diff --git a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
index fc3b8ad7aa..69c914be7d 100644
--- a/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
+++ b/src/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs
@@ -100,7 +100,7 @@ namespace System.IO.Compression
lock (SyncLock)
{
- _inputBufferHandle = inputBuffer.Retain(pin: true);
+ _inputBufferHandle = inputBuffer.Pin();
_zlibStream.NextIn = (IntPtr)_inputBufferHandle.Pointer;
_zlibStream.AvailIn = (uint)inputBuffer.Length;
diff --git a/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs b/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs
index c0d462cd4a..ab7fd35d1b 100644
--- a/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs
+++ b/src/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs
@@ -40,7 +40,7 @@ namespace System.IO.Pipes
_threadPoolBinding = handle;
_state = NoResult;
- _pinnedMemory = bufferToPin.Retain(pin: true);
+ _pinnedMemory = bufferToPin.Pin();
_overlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) =>
{
var completionSource = (PipeCompletionSource<TResult>)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped);
diff --git a/src/System.Memory/ref/System.Memory.cs b/src/System.Memory/ref/System.Memory.cs
index b532f049df..9775637231 100644
--- a/src/System.Memory/ref/System.Memory.cs
+++ b/src/System.Memory/ref/System.Memory.cs
@@ -107,6 +107,7 @@ namespace System
public static implicit operator System.Memory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (System.Memory<T> memory) { throw null; }
public static implicit operator System.Memory<T> (T[] array) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.Memory<T> Slice(int start) { throw null; }
public System.Memory<T> Slice(int start, int length) { throw null; }
@@ -131,6 +132,7 @@ namespace System
public override int GetHashCode() { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (T[] array) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
diff --git a/src/System.Memory/tests/Memory/Pin.cs b/src/System.Memory/tests/Memory/Pin.cs
new file mode 100644
index 0000000000..2d0d8ff523
--- /dev/null
+++ b/src/System.Memory/tests/Memory/Pin.cs
@@ -0,0 +1,133 @@
+// 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.Buffers;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class MemoryTests
+ {
+ [Fact]
+ public static void MemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ Memory<int> memory = array;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryFromEmptyArrayPin()
+ {
+ Memory<int> memory = new int[0];
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void DefaultMemoryPin()
+ {
+ Memory<int> memory = default;
+ MemoryHandle handle = memory.Pin();
+ Assert.False(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer == null);
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ Memory<int> memory = array;
+ memory = memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ Span<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ Memory<int> memory = owner.Memory;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ Memory<int> memory = owner.Memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ Span<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+ }
+}
diff --git a/src/System.Memory/tests/Memory/Retain.cs b/src/System.Memory/tests/Memory/Retain.cs
index 3a33817dff..1ef319103c 100644
--- a/src/System.Memory/tests/Memory/Retain.cs
+++ b/src/System.Memory/tests/Memory/Retain.cs
@@ -46,6 +46,30 @@ namespace System.MemoryTests
}
[Fact]
+ public static void MemoryFromEmptyArrayRetainWithPinning()
+ {
+ Memory<int> memory = new int[0];
+ MemoryHandle handle = memory.Retain(pin: true);
+ Assert.True(handle.HasPointer);
+ handle.Dispose();
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void DefaultMemoryRetain(bool pin)
+ {
+ Memory<int> memory = default;
+ MemoryHandle handle = memory.Retain(pin: pin);
+ Assert.False(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer == null);
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
public static void MemoryRetainWithPinningAndSlice()
{
int[] array = { 1, 2, 3, 4, 5 };
@@ -111,15 +135,6 @@ namespace System.MemoryTests
}
[Fact]
- public static void MemoryFromEmptyArrayRetainWithPinning()
- {
- Memory<int> memory = new int[0];
- MemoryHandle handle = memory.Retain(pin: true);
- Assert.True(handle.HasPointer);
- handle.Dispose();
- }
-
- [Fact]
public static void OwnedMemoryRetainWithPinningAndSlice()
{
int[] array = { 1, 2, 3, 4, 5 };
@@ -146,20 +161,5 @@ namespace System.MemoryTests
}
handle.Dispose();
}
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void DefaultMemoryRetain(bool pin)
- {
- Memory<int> memory = default;
- MemoryHandle handle = memory.Retain(pin: pin);
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
}
}
diff --git a/src/System.Memory/tests/Memory/Strings.cs b/src/System.Memory/tests/Memory/Strings.cs
index 6e4e0bfe05..b711179cd1 100644
--- a/src/System.Memory/tests/Memory/Strings.cs
+++ b/src/System.Memory/tests/Memory/Strings.cs
@@ -57,18 +57,13 @@ namespace System.MemoryTests
}
[Fact]
- public static unsafe void Memory_Retain_ExpectedPointerValue()
+ public static unsafe void Memory_Pin_ExpectedPointerValue()
{
string input = "0123456789";
ReadOnlyMemory<char> readonlyMemory = input.AsMemory();
Memory<char> m = MemoryMarshal.AsMemory(readonlyMemory);
- using (MemoryHandle h = m.Retain(pin: false))
- {
- Assert.Equal(IntPtr.Zero, (IntPtr)h.Pointer);
- }
-
- using (MemoryHandle h = m.Retain(pin: true))
+ using (MemoryHandle h = m.Pin())
{
GC.Collect();
fixed (char* ptr = input)
diff --git a/src/System.Memory/tests/MemoryMarshal/AsMemory.cs b/src/System.Memory/tests/MemoryMarshal/AsMemory.cs
index 43b3ab1c3a..40990d08cb 100644
--- a/src/System.Memory/tests/MemoryMarshal/AsMemory.cs
+++ b/src/System.Memory/tests/MemoryMarshal/AsMemory.cs
@@ -39,17 +39,17 @@ namespace System.MemoryTests
[Theory]
[MemberData(nameof(ReadOnlyMemoryInt32Instances))]
- public static void AsMemory_Roundtrips(ReadOnlyMemory<int> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory);
+ public static void AsMemory_Roundtrips(ReadOnlyMemory<int> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, true);
[Theory]
[MemberData(nameof(ReadOnlyMemoryObjectInstances))]
- public static void AsMemory_Roundtrips(ReadOnlyMemory<object> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory);
+ public static void AsMemory_Roundtrips(ReadOnlyMemory<object> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, false);
[Theory]
[MemberData(nameof(ReadOnlyMemoryCharInstances))]
public static void AsMemory_Roundtrips(ReadOnlyMemory<char> readOnlyMemory)
{
- AsMemory_Roundtrips_Core(readOnlyMemory);
+ AsMemory_Roundtrips_Core(readOnlyMemory, true);
Memory<char> memory = MemoryMarshal.AsMemory(readOnlyMemory);
ReadOnlyMemory<char> readOnlyClone = memory;
@@ -66,7 +66,7 @@ namespace System.MemoryTests
}
}
- private static unsafe void AsMemory_Roundtrips_Core<T>(ReadOnlyMemory<T> readOnlyMemory)
+ private static unsafe void AsMemory_Roundtrips_Core<T>(ReadOnlyMemory<T> readOnlyMemory, bool canBePinned)
{
Memory<T> memory = MemoryMarshal.AsMemory(readOnlyMemory);
ReadOnlyMemory<T> readOnlyClone = memory;
@@ -87,13 +87,16 @@ namespace System.MemoryTests
Assert.Equal(array1.Offset, array2.Offset);
Assert.Equal(array1.Count, array2.Count);
- // Retain
- using (MemoryHandle readOnlyMemoryHandle = readOnlyMemory.Retain())
- using (MemoryHandle readOnlyCloneHandle = readOnlyMemory.Retain())
- using (MemoryHandle memoryHandle = readOnlyMemory.Retain())
+ if (canBePinned)
{
- Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)readOnlyCloneHandle.Pointer);
- Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)memoryHandle.Pointer);
+ // Pin
+ using (MemoryHandle readOnlyMemoryHandle = readOnlyMemory.Pin())
+ using (MemoryHandle readOnlyCloneHandle = readOnlyMemory.Pin())
+ using (MemoryHandle memoryHandle = readOnlyMemory.Pin())
+ {
+ Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)readOnlyCloneHandle.Pointer);
+ Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)memoryHandle.Pointer);
+ }
}
}
}
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Pin.cs b/src/System.Memory/tests/ReadOnlyMemory/Pin.cs
new file mode 100644
index 0000000000..803612035c
--- /dev/null
+++ b/src/System.Memory/tests/ReadOnlyMemory/Pin.cs
@@ -0,0 +1,133 @@
+// 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.Buffers;
+using Xunit;
+
+namespace System.MemoryTests
+{
+ public static partial class ReadOnlyMemoryTests
+ {
+ [Fact]
+ public static void MemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ ReadOnlyMemory<int> memory = array;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryFromEmptyArrayPin()
+ {
+ ReadOnlyMemory<int> memory = new int[0];
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void DefaultMemoryPin()
+ {
+ ReadOnlyMemory<int> memory = default;
+ MemoryHandle handle = memory.Pin();
+ Assert.False(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer == null);
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void MemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ ReadOnlyMemory<int> memory = array;
+ memory = memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ ReadOnlySpan<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPin()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = owner.Memory;
+ MemoryHandle handle = memory.Pin();
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i], pointer[i]);
+ }
+ }
+ handle.Dispose();
+ }
+
+ [Fact]
+ public static void OwnedMemoryPinAndSlice()
+ {
+ int[] array = { 1, 2, 3, 4, 5 };
+ OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
+ ReadOnlyMemory<int> memory = owner.Memory.Slice(1);
+ MemoryHandle handle = memory.Pin();
+ ReadOnlySpan<int> span = memory.Span;
+ Assert.True(handle.HasPointer);
+ unsafe
+ {
+ int* pointer = (int*)handle.Pointer;
+
+ GC.Collect();
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], pointer[i]);
+ }
+
+ for (int i = 0; i < memory.Length; i++)
+ {
+ Assert.Equal(array[i + 1], span[i]);
+ }
+ }
+ handle.Dispose();
+ }
+ }
+}
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Retain.cs b/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
index 6f31b00cd0..d438c78d77 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/Retain.cs
@@ -54,6 +54,21 @@ namespace System.MemoryTests
handle.Dispose();
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public static void DefaultMemoryRetain(bool pin)
+ {
+ ReadOnlyMemory<int> memory = default;
+ MemoryHandle handle = memory.Retain(pin: pin);
+ Assert.False(handle.HasPointer);
+ unsafe
+ {
+ Assert.True(handle.Pointer == null);
+ }
+ handle.Dispose();
+ }
+
[Fact]
public static void MemoryRetainWithPinningAndSlice()
{
@@ -146,20 +161,5 @@ namespace System.MemoryTests
}
handle.Dispose();
}
-
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public static void DefaultMemoryRetain(bool pin)
- {
- ReadOnlyMemory<int> memory = default;
- MemoryHandle handle = memory.Retain(pin: pin);
- Assert.False(handle.HasPointer);
- unsafe
- {
- Assert.True(handle.Pointer == null);
- }
- handle.Dispose();
- }
}
}
diff --git a/src/System.Memory/tests/ReadOnlyMemory/Strings.cs b/src/System.Memory/tests/ReadOnlyMemory/Strings.cs
index ba7e86b8f2..6a775ad87a 100644
--- a/src/System.Memory/tests/ReadOnlyMemory/Strings.cs
+++ b/src/System.Memory/tests/ReadOnlyMemory/Strings.cs
@@ -94,17 +94,12 @@ namespace System.MemoryTests
}
[Fact]
- public static unsafe void AsReadOnlyMemory_Retain_ExpectedPointerValue()
+ public static unsafe void AsReadOnlyMemory_Pin_ExpectedPointerValue()
{
string input = "0123456789";
ReadOnlyMemory<char> m = input.AsMemory();
- using (MemoryHandle h = m.Retain(pin: false))
- {
- Assert.Equal(IntPtr.Zero, (IntPtr)h.Pointer);
- }
-
- using (MemoryHandle h = m.Retain(pin: true))
+ using (MemoryHandle h = m.Pin())
{
GC.Collect();
fixed (char* ptr = input)
@@ -137,7 +132,7 @@ namespace System.MemoryTests
Assert.Equal(length, m.Length);
- using (MemoryHandle h = m.Retain(pin: true))
+ using (MemoryHandle h = m.Pin())
{
fixed (char* pText = text)
{
diff --git a/src/System.Memory/tests/System.Memory.Tests.csproj b/src/System.Memory/tests/System.Memory.Tests.csproj
index 47a328f7f8..27d689a92a 100644
--- a/src/System.Memory/tests/System.Memory.Tests.csproj
+++ b/src/System.Memory/tests/System.Memory.Tests.csproj
@@ -163,6 +163,7 @@
<Compile Include="Memory\GetHashCode.cs" />
<Compile Include="Memory\ImplicitConversion.cs" />
<Compile Include="Memory\OwnedMemory.cs" />
+ <Compile Include="Memory\Pin.cs" />
<Compile Include="Memory\Retain.cs" />
<Compile Include="Memory\Slice.cs" />
<Compile Include="Memory\Span.cs" />
@@ -193,6 +194,7 @@
<Compile Include="ReadOnlyMemory\Equality.cs" />
<Compile Include="ReadOnlyMemory\GetHashCode.cs" />
<Compile Include="ReadOnlyMemory\ImplicitConversion.cs" />
+ <Compile Include="ReadOnlyMemory\Pin.cs" />
<Compile Include="ReadOnlyMemory\Retain.cs" />
<Compile Include="ReadOnlyMemory\Slice.cs" />
<Compile Include="ReadOnlyMemory\Span.cs" />
diff --git a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs
index abccbc36c7..02943cc70f 100644
--- a/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs
+++ b/src/System.Net.Security/src/System/Net/Security/SslStreamPal.OSX.cs
@@ -126,7 +126,7 @@ namespace System.Net.Security
unsafe
{
- MemoryHandle memHandle = input.Retain(pin: true);
+ MemoryHandle memHandle = input.Pin();
try
{
PAL_TlsIo status;
diff --git a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
index bd311d28c9..0caf582202 100644
--- a/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
+++ b/src/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEventArgs.Windows.cs
@@ -183,7 +183,7 @@ namespace System.Net.Sockets
// Return pending and we will continue in the completion port callback.
if (_singleBufferHandleState == SingleBufferHandleState.InProcess)
{
- _singleBufferHandle = _buffer.Retain(pin: true);
+ _singleBufferHandle = _buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
}
return SocketError.IOPending;
@@ -199,7 +199,7 @@ namespace System.Net.Sockets
NativeOverlapped* overlapped = AllocateNativeOverlapped();
try
{
- _singleBufferHandle = buffer.Retain(pin: true);
+ _singleBufferHandle = buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
bool success = socket.AcceptEx(
@@ -234,7 +234,7 @@ namespace System.Net.Sockets
try
{
Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandle = _buffer.Retain(pin: true);
+ _singleBufferHandle = _buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
bool success = socket.ConnectEx(
@@ -472,7 +472,7 @@ namespace System.Net.Sockets
}
Debug.Assert(_singleBufferHandleState == SingleBufferHandleState.None);
- _singleBufferHandle = _buffer.Retain(pin: true);
+ _singleBufferHandle = _buffer.Pin();
_singleBufferHandleState = SingleBufferHandleState.Set;
_wsaRecvMsgWSABufferArray[0].Pointer = (IntPtr)_singleBufferHandle.Pointer;
diff --git a/src/System.Runtime/ref/System.Runtime.cs b/src/System.Runtime/ref/System.Runtime.cs
index eb92a61fce..a5e6822783 100644
--- a/src/System.Runtime/ref/System.Runtime.cs
+++ b/src/System.Runtime/ref/System.Runtime.cs
@@ -1700,6 +1700,7 @@ namespace System
public static implicit operator System.Memory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (System.Memory<T> memory) { throw null; }
public static implicit operator System.Memory<T> (T[] array) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.Memory<T> Slice(int start) { throw null; }
public System.Memory<T> Slice(int start, int length) { throw null; }
@@ -1947,6 +1948,7 @@ namespace System
public override int GetHashCode() { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> segment) { throw null; }
public static implicit operator System.ReadOnlyMemory<T> (T[] array) { throw null; }
+ public System.Buffers.MemoryHandle Pin() { throw null; }
public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
diff --git a/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt b/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt
new file mode 100644
index 0000000000..ba98be8651
--- /dev/null
+++ b/src/System.Runtime/src/ApiCompatBaseline.uapaot.txt
@@ -0,0 +1,4 @@
+Compat issues with assembly System.Runtime:
+MembersMustExist : Member 'System.Memory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ReadOnlyMemory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+Total Issues: 2
diff --git a/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt b/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
index c89c017dc8..181752efce 100644
--- a/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
+++ b/src/shims/ApiCompatBaseline.uapaot.netstandard20.txt
@@ -9,6 +9,10 @@ TypesMustExist : Type 'System.Security.Cryptography.ECCurve' does not exist in t
TypesMustExist : Type 'System.Security.Cryptography.ECParameters' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'System.Security.Cryptography.ECPoint' does not exist in the implementation but it does exist in the contract.
+Compat issues with assembly System.Runtime:
+MembersMustExist : Member 'System.Memory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'System.ReadOnlyMemory<T>.Pin()' does not exist in the implementation but it does exist in the contract.
+
# Compat issues complaining about class vs delegate and class vs struct are because of a bug in APICompat tool where the implementation is picking
# the wrong core assembly. It is picking System.Runtime instead of System.Private.CoreLib, there isn't any straight forward way to fix so baselining.
TypeCannotChangeClassification : Type 'System.Action<T1, T2, T3, T4, T5, T6, T7, T8, T9>' is a 'class' in the implementation but is a 'delegate' in the contract.