From bb5c46859048bfcefca281d7c303540c1217da41 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 28 Mar 2018 20:22:38 -0700 Subject: 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 * 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. --- .../System/IO/FileStreamCompletionSource.Win32.cs | 2 +- src/Common/src/CoreLib/System/Memory.cs | 44 ++++++- src/Common/src/CoreLib/System/ReadOnlyMemory.cs | 38 +++++- .../Interop.OpenSsl.cs | 2 +- .../System/IO/Compression/DeflateZLib/Deflater.cs | 2 +- .../src/System/IO/Pipes/PipeCompletionSource.cs | 2 +- src/System.Memory/ref/System.Memory.cs | 2 + src/System.Memory/tests/Memory/Pin.cs | 133 +++++++++++++++++++++ src/System.Memory/tests/Memory/Retain.cs | 48 ++++---- src/System.Memory/tests/Memory/Strings.cs | 9 +- src/System.Memory/tests/MemoryMarshal/AsMemory.cs | 23 ++-- src/System.Memory/tests/ReadOnlyMemory/Pin.cs | 133 +++++++++++++++++++++ src/System.Memory/tests/ReadOnlyMemory/Retain.cs | 30 ++--- src/System.Memory/tests/ReadOnlyMemory/Strings.cs | 11 +- src/System.Memory/tests/System.Memory.Tests.csproj | 2 + .../src/System/Net/Security/SslStreamPal.OSX.cs | 2 +- .../Net/Sockets/SocketAsyncEventArgs.Windows.cs | 8 +- src/System.Runtime/ref/System.Runtime.cs | 2 + .../src/ApiCompatBaseline.uapaot.txt | 4 + .../ApiCompatBaseline.uapaot.netstandard20.txt | 4 + 20 files changed, 424 insertions(+), 77 deletions(-) create mode 100644 src/System.Memory/tests/Memory/Pin.cs create mode 100644 src/System.Memory/tests/ReadOnlyMemory/Pin.cs create mode 100644 src/System.Runtime/src/ApiCompatBaseline.uapaot.txt 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 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 destination) => Span.TryCopyTo(destination.Span); /// - /// Returns a handle for the array. - /// If pin is true, the GC will not move the array and hence its address can be taken + /// Creates a handle for the memory. + /// The GC will not move the array until the returned + /// is disposed, enabling taking and using the memory's address. /// + public unsafe MemoryHandle Pin() + { + if (_index < 0) + { + return ((OwnedMemory)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf()); + } + else if (typeof(T) == typeof(char) && _object is string s) + { + // This case can only happen if a ReadOnlyMemory was created around a string + // and then that was cast to a Memory using unsafe / marshaling code. This needs + // to work, however, so that code that uses a single Memory field to store either + // a readable ReadOnlyMemory or a writable Memory can still be pinned and + // used for interop purposes. + GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned); +#if FEATURE_PORTABLE_SPAN + void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); +#else + void* pointer = Unsafe.Add(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((void*)handle.AddrOfPinnedObject(), _index); +#else + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); +#endif // FEATURE_PORTABLE_SPAN + return new MemoryHandle(null, pointer, handle); + } + return default; + } + + /// [Obsolete, use Pin()] Creates a handle for the memory. + /// + /// If pin is true, the GC will not move the array until the returned + /// is disposed, enabling taking and using the memory's address. + /// 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 /// The span to copy items into. public bool TryCopyTo(Memory destination) => Span.TryCopyTo(destination.Span); - /// Creates a handle for the memory. + /// + /// Creates a handle for the memory. + /// The GC will not move the array until the returned + /// is disposed, enabling taking and using the memory's address. + /// + public unsafe MemoryHandle Pin() + { + if (_index < 0) + { + return ((OwnedMemory)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf()); + } + 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((void*)handle.AddrOfPinnedObject(), _index); +#else + void* pointer = Unsafe.Add(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((void*)handle.AddrOfPinnedObject(), _index); +#else + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); +#endif // FEATURE_PORTABLE_SPAN + return new MemoryHandle(null, pointer, handle); + } + return default; + } + + /// [Obsolete, use Pin()] Creates a handle for the memory. /// /// If pin is true, the GC will not move the array until the returned - /// is disposed, enabling the memory's address can be taken and used. + /// is disposed, enabling taking and using the memory's address. /// 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)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 (System.ArraySegment segment) { throw null; } public static implicit operator System.ReadOnlyMemory (System.Memory memory) { throw null; } public static implicit operator System.Memory (T[] array) { throw null; } + public System.Buffers.MemoryHandle Pin() { throw null; } public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; } public System.Memory Slice(int start) { throw null; } public System.Memory 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 (System.ArraySegment segment) { throw null; } public static implicit operator System.ReadOnlyMemory (T[] array) { throw null; } + public System.Buffers.MemoryHandle Pin() { throw null; } public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; } public System.ReadOnlyMemory Slice(int start) { throw null; } public System.ReadOnlyMemory 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 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 memory = new int[0]; + MemoryHandle handle = memory.Pin(); + Assert.True(handle.HasPointer); + handle.Dispose(); + } + + [Fact] + public static void DefaultMemoryPin() + { + Memory 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 memory = array; + memory = memory.Slice(1); + MemoryHandle handle = memory.Pin(); + Span 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 owner = new CustomMemoryForTest(array); + Memory 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 owner = new CustomMemoryForTest(array); + Memory memory = owner.Memory.Slice(1); + MemoryHandle handle = memory.Pin(); + Span 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 @@ -45,6 +45,30 @@ namespace System.MemoryTests handle.Dispose(); } + [Fact] + public static void MemoryFromEmptyArrayRetainWithPinning() + { + Memory 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 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() { @@ -110,15 +134,6 @@ namespace System.MemoryTests handle.Dispose(); } - [Fact] - public static void MemoryFromEmptyArrayRetainWithPinning() - { - Memory memory = new int[0]; - MemoryHandle handle = memory.Retain(pin: true); - Assert.True(handle.HasPointer); - handle.Dispose(); - } - [Fact] public static void OwnedMemoryRetainWithPinningAndSlice() { @@ -146,20 +161,5 @@ namespace System.MemoryTests } handle.Dispose(); } - - [Theory] - [InlineData(true)] - [InlineData(false)] - public static void DefaultMemoryRetain(bool pin) - { - Memory 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 readonlyMemory = input.AsMemory(); Memory 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 readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory); + public static void AsMemory_Roundtrips(ReadOnlyMemory readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, true); [Theory] [MemberData(nameof(ReadOnlyMemoryObjectInstances))] - public static void AsMemory_Roundtrips(ReadOnlyMemory readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory); + public static void AsMemory_Roundtrips(ReadOnlyMemory readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, false); [Theory] [MemberData(nameof(ReadOnlyMemoryCharInstances))] public static void AsMemory_Roundtrips(ReadOnlyMemory readOnlyMemory) { - AsMemory_Roundtrips_Core(readOnlyMemory); + AsMemory_Roundtrips_Core(readOnlyMemory, true); Memory memory = MemoryMarshal.AsMemory(readOnlyMemory); ReadOnlyMemory readOnlyClone = memory; @@ -66,7 +66,7 @@ namespace System.MemoryTests } } - private static unsafe void AsMemory_Roundtrips_Core(ReadOnlyMemory readOnlyMemory) + private static unsafe void AsMemory_Roundtrips_Core(ReadOnlyMemory readOnlyMemory, bool canBePinned) { Memory memory = MemoryMarshal.AsMemory(readOnlyMemory); ReadOnlyMemory 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 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 memory = new int[0]; + MemoryHandle handle = memory.Pin(); + Assert.True(handle.HasPointer); + handle.Dispose(); + } + + [Fact] + public static void DefaultMemoryPin() + { + ReadOnlyMemory 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 memory = array; + memory = memory.Slice(1); + MemoryHandle handle = memory.Pin(); + ReadOnlySpan 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 owner = new CustomMemoryForTest(array); + ReadOnlyMemory 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 owner = new CustomMemoryForTest(array); + ReadOnlyMemory memory = owner.Memory.Slice(1); + MemoryHandle handle = memory.Pin(); + ReadOnlySpan 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 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 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 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 @@ + @@ -193,6 +194,7 @@ + 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 (System.ArraySegment segment) { throw null; } public static implicit operator System.ReadOnlyMemory (System.Memory memory) { throw null; } public static implicit operator System.Memory (T[] array) { throw null; } + public System.Buffers.MemoryHandle Pin() { throw null; } public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; } public System.Memory Slice(int start) { throw null; } public System.Memory 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 (System.ArraySegment segment) { throw null; } public static implicit operator System.ReadOnlyMemory (T[] array) { throw null; } + public System.Buffers.MemoryHandle Pin() { throw null; } public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; } public System.ReadOnlyMemory Slice(int start) { throw null; } public System.ReadOnlyMemory 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.Pin()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'System.ReadOnlyMemory.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.Pin()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'System.ReadOnlyMemory.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' is a 'class' in the implementation but is a 'delegate' in the contract. -- cgit v1.2.3