From 0578152ed085597fd5e7f35e63ac2b9b4a5a7f28 Mon Sep 17 00:00:00 2001 From: Ahson Khan Date: Tue, 27 Mar 2018 17:05:33 -0700 Subject: [PATCH] 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. --- src/mscorlib/shared/System/Memory.cs | 44 +++++++++++++++++++- src/mscorlib/shared/System/ReadOnlyMemory.cs | 38 ++++++++++++++++- 2 files changed, 78 insertions(+), 4 deletions(-) diff --git a/src/mscorlib/shared/System/Memory.cs b/src/mscorlib/shared/System/Memory.cs index 508ebcb3ee..bb2b1557a9 100644 --- a/src/mscorlib/shared/System/Memory.cs +++ b/src/mscorlib/shared/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/mscorlib/shared/System/ReadOnlyMemory.cs b/src/mscorlib/shared/System/ReadOnlyMemory.cs index 5f3f0e1980..dca7db3dfd 100644 --- a/src/mscorlib/shared/System/ReadOnlyMemory.cs +++ b/src/mscorlib/shared/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) { -- 2.34.1