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

Commit df9dce8

Browse files
stephentoubsafern
authored andcommitted
Optimize Memory<T> to ReadOnlyMemory<T> cast (dotnet/coreclr#14309)
They have the same layout; we can just use Unsafe.As. In a microbenchmark that just repeatedly reads from a `Memory<byte>` field and writes it to a `ReadOnlyMemory<byte>` field, this doubles throughput. Signed-off-by: dotnet-bot-corefx-mirror <dotnet-bot@microsoft.com>
1 parent 64c04e2 commit df9dce8

File tree

2 files changed

+9
-8
lines changed

2 files changed

+9
-8
lines changed

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

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ namespace System
1616
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
1717
public struct Memory<T>
1818
{
19+
// NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
20+
// as code uses Unsafe.As to cast between them.
21+
1922
// The highest order bit of _index is used to discern whether _arrayOrOwnedMemory is an array or an owned memory
2023
// if (_index >> 31) == 1, object _arrayOrOwnedMemory is an OwnedMemory<T>
2124
// else, object _arrayOrOwnedMemory is a T[]
@@ -100,13 +103,8 @@ internal Memory(OwnedMemory<T> owner, int index, int length)
100103
/// <summary>
101104
/// Defines an implicit conversion of a <see cref="Memory{T}"/> to a <see cref="ReadOnlyMemory{T}"/>
102105
/// </summary>
103-
[MethodImpl(MethodImplOptions.AggressiveInlining)]
104-
public static implicit operator ReadOnlyMemory<T>(Memory<T> memory)
105-
{
106-
if (memory._index < 0)
107-
return new ReadOnlyMemory<T>((OwnedMemory<T>)memory._arrayOrOwnedMemory, memory._index & RemoveOwnedFlagBitMask, memory._length);
108-
return new ReadOnlyMemory<T>((T[])memory._arrayOrOwnedMemory, memory._index, memory._length);
109-
}
106+
public static implicit operator ReadOnlyMemory<T>(Memory<T> memory) =>
107+
Unsafe.As<Memory<T>, ReadOnlyMemory<T>>(ref memory);
110108

111109
//Debugger Display = {T[length]}
112110
private string DebuggerDisplay => string.Format("{{{0}[{1}]}}", typeof(T).Name, _length);

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ namespace System
1616
[DebuggerTypeProxy(typeof(MemoryDebugView<>))]
1717
public struct ReadOnlyMemory<T>
1818
{
19+
// NOTE: With the current implementation, Memory<T> and ReadOnlyMemory<T> must have the same layout,
20+
// as code uses Unsafe.As to cast between them.
21+
1922
// The highest order bit of _index is used to discern whether _arrayOrOwnedMemory is an array or an owned memory
2023
// if (_index >> 31) == 1, object _arrayOrOwnedMemory is an OwnedMemory<T>
2124
// else, object _arrayOrOwnedMemory is a T[]
@@ -273,4 +276,4 @@ private static int CombineHashCodes(int h1, int h2, int h3)
273276
}
274277

275278
}
276-
}
279+
}

0 commit comments

Comments
 (0)