diff --git a/src/mscorlib/shared/System/Memory.cs b/src/mscorlib/shared/System/Memory.cs index 26f4e4ce1942..c06b1b4d9afa 100644 --- a/src/mscorlib/shared/System/Memory.cs +++ b/src/mscorlib/shared/System/Memory.cs @@ -318,8 +318,11 @@ public Span Span /// /// Creates a handle for the memory. - /// The GC will not move the array until the returned + /// The GC will not move the memory until the returned /// is disposed, enabling taking and using the memory's address. + /// + /// An instance with nonprimitive (non-blittable) members cannot be pinned. + /// /// public unsafe MemoryHandle Pin() { @@ -345,13 +348,26 @@ public unsafe MemoryHandle Pin() } else if (_object is T[] array) { - GCHandle handle = _length < 0 ? default : GCHandle.Alloc(array, GCHandleType.Pinned); + // Array is already pre-pinned + if (_length < 0) + { #if FEATURE_PORTABLE_SPAN - void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref MemoryMarshal.GetReference(array)), _index); #else - void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); #endif // FEATURE_PORTABLE_SPAN - return new MemoryHandle(pointer, handle); + return new MemoryHandle(pointer); + } + else + { + GCHandle 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(pointer, handle); + } } return default; } diff --git a/src/mscorlib/shared/System/ReadOnlyMemory.cs b/src/mscorlib/shared/System/ReadOnlyMemory.cs index 3e7884528edb..91a35225a3dc 100644 --- a/src/mscorlib/shared/System/ReadOnlyMemory.cs +++ b/src/mscorlib/shared/System/ReadOnlyMemory.cs @@ -235,8 +235,11 @@ public ReadOnlySpan Span /// /// Creates a handle for the memory. - /// The GC will not move the array until the returned + /// The GC will not move the memory until the returned /// is disposed, enabling taking and using the memory's address. + /// + /// An instance with nonprimitive (non-blittable) members cannot be pinned. + /// /// public unsafe MemoryHandle Pin() { @@ -257,13 +260,26 @@ public unsafe MemoryHandle Pin() } else if (_object is T[] array) { - GCHandle handle = _length < 0 ? default : GCHandle.Alloc(array, GCHandleType.Pinned); + // Array is already pre-pinned + if (_length < 0) + { #if FEATURE_PORTABLE_SPAN - void* pointer = Unsafe.Add((void*)handle.AddrOfPinnedObject(), _index); + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref MemoryMarshal.GetReference(array)), _index); #else - void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); + void* pointer = Unsafe.Add(Unsafe.AsPointer(ref array.GetRawSzArrayData()), _index); #endif // FEATURE_PORTABLE_SPAN - return new MemoryHandle(pointer, handle); + return new MemoryHandle(pointer); + } + else + { + GCHandle 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(pointer, handle); + } } return default; }