Skip to content

Commit 537203b

Browse files
committed
Minor codegen improvements
1 parent c343c79 commit 537203b

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

Microsoft.Toolkit.HighPerformance/Buffers/MemoryOwner{T}.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
using System.Diagnostics;
88
using System.Diagnostics.Contracts;
99
using System.Runtime.CompilerServices;
10+
#if NETCORE_RUNTIME
11+
using System.Runtime.InteropServices;
12+
#endif
1013
using Microsoft.Toolkit.HighPerformance.Buffers.Views;
1114
using Microsoft.Toolkit.HighPerformance.Extensions;
1215

@@ -180,7 +183,22 @@ public Span<T> Span
180183
ThrowObjectDisposedException();
181184
}
182185

186+
#if NETCORE_RUNTIME
187+
ref T r0 = ref array!.DangerousGetReferenceAt(this.start);
188+
189+
// On .NET Core runtimes, we can manually create a span from the starting reference to
190+
// skip the argument validations, which include an explicit null check, covariance check
191+
// for the array and the actual validation for the starting offset and target length. We
192+
// only do this on .NET Core as we can leverage the runtime-specific array layout to get
193+
// a fast access to the initial element, which makes this trick worth it. Otherwise, on
194+
// runtimes where we would need to at least access a static field to retrieve the base
195+
// byte offset within an SZ array object, we can get better performance by just using the
196+
// default Span<T> constructor and paying the cost of the extra conditional branches,
197+
// especially if T is a value type, in which case the covariance check is JIT removed.
198+
return MemoryMarshal.CreateSpan(ref r0, this.length);
199+
#else
183200
return new Span<T>(array!, this.start, this.length);
201+
#endif
184202
}
185203
}
186204

Microsoft.Toolkit.HighPerformance/Buffers/SpanOwner{T}.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77
using System.Diagnostics;
88
using System.Diagnostics.Contracts;
99
using System.Runtime.CompilerServices;
10+
#if NETCORE_RUNTIME
11+
using System.Runtime.InteropServices;
12+
#endif
1013
using Microsoft.Toolkit.HighPerformance.Buffers.Views;
1114
using Microsoft.Toolkit.HighPerformance.Extensions;
1215

@@ -143,7 +146,16 @@ public int Length
143146
public Span<T> Span
144147
{
145148
[MethodImpl(MethodImplOptions.AggressiveInlining)]
146-
get => new Span<T>(this.array, 0, this.length);
149+
get
150+
{
151+
#if NETCORE_RUNTIME
152+
ref T r0 = ref array!.DangerousGetReference();
153+
154+
return MemoryMarshal.CreateSpan(ref r0, this.length);
155+
#else
156+
return new Span<T>(this.array, 0, this.length);
157+
#endif
158+
}
147159
}
148160

149161
/// <summary>

0 commit comments

Comments
 (0)