Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 5c53bdc

Browse files
ahsonkhandotnet-bot
authored andcommitted
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>
1 parent 305bebc commit 5c53bdc

File tree

2 files changed

+78
-4
lines changed

2 files changed

+78
-4
lines changed

src/Common/src/CoreLib/System/Memory.cs

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,9 +270,49 @@ public Span<T> Span
270270
public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
271271

272272
/// <summary>
273-
/// Returns a handle for the array.
274-
/// <param name="pin">If pin is true, the GC will not move the array and hence its address can be taken</param>
273+
/// Creates a handle for the memory.
274+
/// The GC will not move the array until the returned <see cref="MemoryHandle"/>
275+
/// is disposed, enabling taking and using the memory's address.
275276
/// </summary>
277+
public unsafe MemoryHandle Pin()
278+
{
279+
if (_index < 0)
280+
{
281+
return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
282+
}
283+
else if (typeof(T) == typeof(char) && _object is string s)
284+
{
285+
// This case can only happen if a ReadOnlyMemory<char> was created around a string
286+
// and then that was cast to a Memory<char> using unsafe / marshaling code. This needs
287+
// to work, however, so that code that uses a single Memory<char> field to store either
288+
// a readable ReadOnlyMemory<char> or a writable Memory<char> can still be pinned and
289+
// used for interop purposes.
290+
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
291+
#if FEATURE_PORTABLE_SPAN
292+
void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
293+
#else
294+
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
295+
#endif // FEATURE_PORTABLE_SPAN
296+
return new MemoryHandle(null, pointer, handle);
297+
}
298+
else if (_object is T[] array)
299+
{
300+
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
301+
#if FEATURE_PORTABLE_SPAN
302+
void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
303+
#else
304+
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
305+
#endif // FEATURE_PORTABLE_SPAN
306+
return new MemoryHandle(null, pointer, handle);
307+
}
308+
return default;
309+
}
310+
311+
/// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
312+
/// <param name="pin">
313+
/// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
314+
/// is disposed, enabling taking and using the memory's address.
315+
/// </param>
276316
public unsafe MemoryHandle Retain(bool pin = false)
277317
{
278318
MemoryHandle memoryHandle = default;

src/Common/src/CoreLib/System/ReadOnlyMemory.cs

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,10 +226,44 @@ public ReadOnlySpan<T> Span
226226
/// <param name="destination">The span to copy items into.</param>
227227
public bool TryCopyTo(Memory<T> destination) => Span.TryCopyTo(destination.Span);
228228

229-
/// <summary>Creates a handle for the memory.</summary>
229+
/// <summary>
230+
/// Creates a handle for the memory.
231+
/// The GC will not move the array until the returned <see cref="MemoryHandle"/>
232+
/// is disposed, enabling taking and using the memory's address.
233+
/// </summary>
234+
public unsafe MemoryHandle Pin()
235+
{
236+
if (_index < 0)
237+
{
238+
return ((OwnedMemory<T>)_object).Pin((_index & RemoveOwnedFlagBitMask) * Unsafe.SizeOf<T>());
239+
}
240+
else if (typeof(T) == typeof(char) && _object is string s)
241+
{
242+
GCHandle handle = GCHandle.Alloc(s, GCHandleType.Pinned);
243+
#if FEATURE_PORTABLE_SPAN
244+
void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
245+
#else
246+
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref s.GetRawStringData()), _index);
247+
#endif // FEATURE_PORTABLE_SPAN
248+
return new MemoryHandle(null, pointer, handle);
249+
}
250+
else if (_object is T[] array)
251+
{
252+
var handle = GCHandle.Alloc(array, GCHandleType.Pinned);
253+
#if FEATURE_PORTABLE_SPAN
254+
void* pointer = Unsafe.Add<T>((void*)handle.AddrOfPinnedObject(), _index);
255+
#else
256+
void* pointer = Unsafe.Add<T>(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index);
257+
#endif // FEATURE_PORTABLE_SPAN
258+
return new MemoryHandle(null, pointer, handle);
259+
}
260+
return default;
261+
}
262+
263+
/// <summary>[Obsolete, use Pin()] Creates a handle for the memory.</summary>
230264
/// <param name="pin">
231265
/// If pin is true, the GC will not move the array until the returned <see cref="MemoryHandle"/>
232-
/// is disposed, enabling the memory's address can be taken and used.
266+
/// is disposed, enabling taking and using the memory's address.
233267
/// </param>
234268
public unsafe MemoryHandle Retain(bool pin = false)
235269
{

0 commit comments

Comments
 (0)