Skip to content

Commit c31efe6

Browse files
dotnet-botahsonkhan
authored andcommitted
Mirror changes from dotnet/coreclr (dotnet/corefx#28534)
* Adding Memory.Pin() to eventually replace Memory.Retain(bool) (dotnet/corefx#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. Commit migrated from dotnet/corefx@bb5c468
1 parent 68e8e69 commit c31efe6

File tree

17 files changed

+345
-72
lines changed

17 files changed

+345
-72
lines changed

src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.OpenSsl.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ internal static int Encrypt(SafeSslHandle context, ReadOnlyMemory<byte> input, r
232232
int retVal;
233233
unsafe
234234
{
235-
using (MemoryHandle handle = input.Retain(pin: true))
235+
using (MemoryHandle handle = input.Pin())
236236
{
237237
retVal = Ssl.SslWrite(context, (byte*)handle.Pointer, input.Length);
238238
}

src/libraries/System.IO.Compression/src/System/IO/Compression/DeflateZLib/Deflater.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ internal unsafe void SetInput(ReadOnlyMemory<byte> inputBuffer)
100100

101101
lock (SyncLock)
102102
{
103-
_inputBufferHandle = inputBuffer.Retain(pin: true);
103+
_inputBufferHandle = inputBuffer.Pin();
104104

105105
_zlibStream.NextIn = (IntPtr)_inputBufferHandle.Pointer;
106106
_zlibStream.AvailIn = (uint)inputBuffer.Length;

src/libraries/System.IO.Pipes/src/System/IO/Pipes/PipeCompletionSource.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ protected PipeCompletionSource(ThreadPoolBoundHandle handle, ReadOnlyMemory<byte
4040
_threadPoolBinding = handle;
4141
_state = NoResult;
4242

43-
_pinnedMemory = bufferToPin.Retain(pin: true);
43+
_pinnedMemory = bufferToPin.Pin();
4444
_overlapped = _threadPoolBinding.AllocateNativeOverlapped((errorCode, numBytes, pOverlapped) =>
4545
{
4646
var completionSource = (PipeCompletionSource<TResult>)ThreadPoolBoundHandle.GetNativeOverlappedState(pOverlapped);

src/libraries/System.Memory/ref/System.Memory.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ public void CopyTo(System.Memory<T> destination) { }
107107
public static implicit operator System.Memory<T> (System.ArraySegment<T> segment) { throw null; }
108108
public static implicit operator System.ReadOnlyMemory<T> (System.Memory<T> memory) { throw null; }
109109
public static implicit operator System.Memory<T> (T[] array) { throw null; }
110+
public System.Buffers.MemoryHandle Pin() { throw null; }
110111
public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
111112
public System.Memory<T> Slice(int start) { throw null; }
112113
public System.Memory<T> Slice(int start, int length) { throw null; }
@@ -131,6 +132,7 @@ public void CopyTo(System.Memory<T> destination) { }
131132
public override int GetHashCode() { throw null; }
132133
public static implicit operator System.ReadOnlyMemory<T> (System.ArraySegment<T> segment) { throw null; }
133134
public static implicit operator System.ReadOnlyMemory<T> (T[] array) { throw null; }
135+
public System.Buffers.MemoryHandle Pin() { throw null; }
134136
public System.Buffers.MemoryHandle Retain(bool pin = false) { throw null; }
135137
public System.ReadOnlyMemory<T> Slice(int start) { throw null; }
136138
public System.ReadOnlyMemory<T> Slice(int start, int length) { throw null; }
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Buffers;
6+
using Xunit;
7+
8+
namespace System.MemoryTests
9+
{
10+
public static partial class MemoryTests
11+
{
12+
[Fact]
13+
public static void MemoryPin()
14+
{
15+
int[] array = { 1, 2, 3, 4, 5 };
16+
Memory<int> memory = array;
17+
MemoryHandle handle = memory.Pin();
18+
Assert.True(handle.HasPointer);
19+
unsafe
20+
{
21+
int* pointer = (int*)handle.Pointer;
22+
23+
GC.Collect();
24+
25+
for (int i = 0; i < memory.Length; i++)
26+
{
27+
Assert.Equal(array[i], pointer[i]);
28+
}
29+
}
30+
handle.Dispose();
31+
}
32+
33+
[Fact]
34+
public static void MemoryFromEmptyArrayPin()
35+
{
36+
Memory<int> memory = new int[0];
37+
MemoryHandle handle = memory.Pin();
38+
Assert.True(handle.HasPointer);
39+
handle.Dispose();
40+
}
41+
42+
[Fact]
43+
public static void DefaultMemoryPin()
44+
{
45+
Memory<int> memory = default;
46+
MemoryHandle handle = memory.Pin();
47+
Assert.False(handle.HasPointer);
48+
unsafe
49+
{
50+
Assert.True(handle.Pointer == null);
51+
}
52+
handle.Dispose();
53+
}
54+
55+
[Fact]
56+
public static void MemoryPinAndSlice()
57+
{
58+
int[] array = { 1, 2, 3, 4, 5 };
59+
Memory<int> memory = array;
60+
memory = memory.Slice(1);
61+
MemoryHandle handle = memory.Pin();
62+
Span<int> span = memory.Span;
63+
Assert.True(handle.HasPointer);
64+
unsafe
65+
{
66+
int* pointer = (int*)handle.Pointer;
67+
68+
GC.Collect();
69+
70+
for (int i = 0; i < memory.Length; i++)
71+
{
72+
Assert.Equal(array[i + 1], pointer[i]);
73+
}
74+
75+
for (int i = 0; i < memory.Length; i++)
76+
{
77+
Assert.Equal(array[i + 1], span[i]);
78+
}
79+
}
80+
handle.Dispose();
81+
}
82+
83+
[Fact]
84+
public static void OwnedMemoryPin()
85+
{
86+
int[] array = { 1, 2, 3, 4, 5 };
87+
OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
88+
Memory<int> memory = owner.Memory;
89+
MemoryHandle handle = memory.Pin();
90+
Assert.True(handle.HasPointer);
91+
unsafe
92+
{
93+
int* pointer = (int*)handle.Pointer;
94+
95+
GC.Collect();
96+
97+
for (int i = 0; i < memory.Length; i++)
98+
{
99+
Assert.Equal(array[i], pointer[i]);
100+
}
101+
}
102+
handle.Dispose();
103+
}
104+
105+
[Fact]
106+
public static void OwnedMemoryPinAndSlice()
107+
{
108+
int[] array = { 1, 2, 3, 4, 5 };
109+
OwnedMemory<int> owner = new CustomMemoryForTest<int>(array);
110+
Memory<int> memory = owner.Memory.Slice(1);
111+
MemoryHandle handle = memory.Pin();
112+
Span<int> span = memory.Span;
113+
Assert.True(handle.HasPointer);
114+
unsafe
115+
{
116+
int* pointer = (int*)handle.Pointer;
117+
118+
GC.Collect();
119+
120+
for (int i = 0; i < memory.Length; i++)
121+
{
122+
Assert.Equal(array[i + 1], pointer[i]);
123+
}
124+
125+
for (int i = 0; i < memory.Length; i++)
126+
{
127+
Assert.Equal(array[i + 1], span[i]);
128+
}
129+
}
130+
handle.Dispose();
131+
}
132+
}
133+
}

src/libraries/System.Memory/tests/Memory/Retain.cs

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,30 @@ public static void MemoryRetainWithPinning()
4545
handle.Dispose();
4646
}
4747

48+
[Fact]
49+
public static void MemoryFromEmptyArrayRetainWithPinning()
50+
{
51+
Memory<int> memory = new int[0];
52+
MemoryHandle handle = memory.Retain(pin: true);
53+
Assert.True(handle.HasPointer);
54+
handle.Dispose();
55+
}
56+
57+
[Theory]
58+
[InlineData(true)]
59+
[InlineData(false)]
60+
public static void DefaultMemoryRetain(bool pin)
61+
{
62+
Memory<int> memory = default;
63+
MemoryHandle handle = memory.Retain(pin: pin);
64+
Assert.False(handle.HasPointer);
65+
unsafe
66+
{
67+
Assert.True(handle.Pointer == null);
68+
}
69+
handle.Dispose();
70+
}
71+
4872
[Fact]
4973
public static void MemoryRetainWithPinningAndSlice()
5074
{
@@ -110,15 +134,6 @@ public static void OwnedMemoryRetainWithPinning()
110134
handle.Dispose();
111135
}
112136

113-
[Fact]
114-
public static void MemoryFromEmptyArrayRetainWithPinning()
115-
{
116-
Memory<int> memory = new int[0];
117-
MemoryHandle handle = memory.Retain(pin: true);
118-
Assert.True(handle.HasPointer);
119-
handle.Dispose();
120-
}
121-
122137
[Fact]
123138
public static void OwnedMemoryRetainWithPinningAndSlice()
124139
{
@@ -146,20 +161,5 @@ public static void OwnedMemoryRetainWithPinningAndSlice()
146161
}
147162
handle.Dispose();
148163
}
149-
150-
[Theory]
151-
[InlineData(true)]
152-
[InlineData(false)]
153-
public static void DefaultMemoryRetain(bool pin)
154-
{
155-
Memory<int> memory = default;
156-
MemoryHandle handle = memory.Retain(pin: pin);
157-
Assert.False(handle.HasPointer);
158-
unsafe
159-
{
160-
Assert.True(handle.Pointer == null);
161-
}
162-
handle.Dispose();
163-
}
164164
}
165165
}

src/libraries/System.Memory/tests/Memory/Strings.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,13 @@ public static void Memory_Slice_MatchesSubstring(string input, int offset, int c
5757
}
5858

5959
[Fact]
60-
public static unsafe void Memory_Retain_ExpectedPointerValue()
60+
public static unsafe void Memory_Pin_ExpectedPointerValue()
6161
{
6262
string input = "0123456789";
6363
ReadOnlyMemory<char> readonlyMemory = input.AsMemory();
6464
Memory<char> m = MemoryMarshal.AsMemory(readonlyMemory);
6565

66-
using (MemoryHandle h = m.Retain(pin: false))
67-
{
68-
Assert.Equal(IntPtr.Zero, (IntPtr)h.Pointer);
69-
}
70-
71-
using (MemoryHandle h = m.Retain(pin: true))
66+
using (MemoryHandle h = m.Pin())
7267
{
7368
GC.Collect();
7469
fixed (char* ptr = input)

src/libraries/System.Memory/tests/MemoryMarshal/AsMemory.cs

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,17 +39,17 @@ public static IEnumerable<object[]> ReadOnlyMemoryCharInstances()
3939

4040
[Theory]
4141
[MemberData(nameof(ReadOnlyMemoryInt32Instances))]
42-
public static void AsMemory_Roundtrips(ReadOnlyMemory<int> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory);
42+
public static void AsMemory_Roundtrips(ReadOnlyMemory<int> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, true);
4343

4444
[Theory]
4545
[MemberData(nameof(ReadOnlyMemoryObjectInstances))]
46-
public static void AsMemory_Roundtrips(ReadOnlyMemory<object> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory);
46+
public static void AsMemory_Roundtrips(ReadOnlyMemory<object> readOnlyMemory) => AsMemory_Roundtrips_Core(readOnlyMemory, false);
4747

4848
[Theory]
4949
[MemberData(nameof(ReadOnlyMemoryCharInstances))]
5050
public static void AsMemory_Roundtrips(ReadOnlyMemory<char> readOnlyMemory)
5151
{
52-
AsMemory_Roundtrips_Core(readOnlyMemory);
52+
AsMemory_Roundtrips_Core(readOnlyMemory, true);
5353

5454
Memory<char> memory = MemoryMarshal.AsMemory(readOnlyMemory);
5555
ReadOnlyMemory<char> readOnlyClone = memory;
@@ -66,7 +66,7 @@ public static void AsMemory_Roundtrips(ReadOnlyMemory<char> readOnlyMemory)
6666
}
6767
}
6868

69-
private static unsafe void AsMemory_Roundtrips_Core<T>(ReadOnlyMemory<T> readOnlyMemory)
69+
private static unsafe void AsMemory_Roundtrips_Core<T>(ReadOnlyMemory<T> readOnlyMemory, bool canBePinned)
7070
{
7171
Memory<T> memory = MemoryMarshal.AsMemory(readOnlyMemory);
7272
ReadOnlyMemory<T> readOnlyClone = memory;
@@ -87,13 +87,16 @@ private static unsafe void AsMemory_Roundtrips_Core<T>(ReadOnlyMemory<T> readOnl
8787
Assert.Equal(array1.Offset, array2.Offset);
8888
Assert.Equal(array1.Count, array2.Count);
8989

90-
// Retain
91-
using (MemoryHandle readOnlyMemoryHandle = readOnlyMemory.Retain())
92-
using (MemoryHandle readOnlyCloneHandle = readOnlyMemory.Retain())
93-
using (MemoryHandle memoryHandle = readOnlyMemory.Retain())
90+
if (canBePinned)
9491
{
95-
Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)readOnlyCloneHandle.Pointer);
96-
Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)memoryHandle.Pointer);
92+
// Pin
93+
using (MemoryHandle readOnlyMemoryHandle = readOnlyMemory.Pin())
94+
using (MemoryHandle readOnlyCloneHandle = readOnlyMemory.Pin())
95+
using (MemoryHandle memoryHandle = readOnlyMemory.Pin())
96+
{
97+
Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)readOnlyCloneHandle.Pointer);
98+
Assert.Equal((IntPtr)readOnlyMemoryHandle.Pointer, (IntPtr)memoryHandle.Pointer);
99+
}
97100
}
98101
}
99102
}

0 commit comments

Comments
 (0)