Skip to content

Commit 94abcab

Browse files
authored
Optimize some SegmentedArrayHelper members for JIT (#67558)
1 parent 75ab617 commit 94abcab

2 files changed

Lines changed: 41 additions & 14 deletions

File tree

src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,12 @@ internal static class SegmentedArrayHelper
1616
// Large value types may benefit from a smaller number.
1717
internal const int IntrosortSizeThreshold = 16;
1818

19-
/// <summary>
20-
/// A combination of <see cref="MethodImplOptions.AggressiveInlining"/> and
21-
/// <see cref="F:System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization"/>.
22-
/// </summary>
23-
[SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The field is not supported in all compilation targets.")]
24-
internal const MethodImplOptions FastPathMethodImplOptions = MethodImplOptions.AggressiveInlining | (MethodImplOptions)512;
25-
26-
[MethodImpl(FastPathMethodImplOptions)]
19+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2720
internal static int GetSegmentSize<T>()
2821
{
22+
#if NETCOREAPP3_0_OR_NEWER
23+
return InlineCalculateSegmentSize(Unsafe.SizeOf<T>());
24+
#else
2925
if (Unsafe.SizeOf<T>() == Unsafe.SizeOf<object>())
3026
{
3127
return ReferenceTypeSegmentHelper.SegmentSize;
@@ -34,11 +30,15 @@ internal static int GetSegmentSize<T>()
3430
{
3531
return ValueTypeSegmentHelper<T>.SegmentSize;
3632
}
33+
#endif
3734
}
3835

39-
[MethodImpl(FastPathMethodImplOptions)]
36+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
4037
internal static int GetSegmentShift<T>()
4138
{
39+
#if NETCOREAPP3_0_OR_NEWER
40+
return InlineCalculateSegmentShift(Unsafe.SizeOf<T>());
41+
#else
4242
if (Unsafe.SizeOf<T>() == Unsafe.SizeOf<object>())
4343
{
4444
return ReferenceTypeSegmentHelper.SegmentShift;
@@ -47,11 +47,15 @@ internal static int GetSegmentShift<T>()
4747
{
4848
return ValueTypeSegmentHelper<T>.SegmentShift;
4949
}
50+
#endif
5051
}
5152

52-
[MethodImpl(FastPathMethodImplOptions)]
53+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
5354
internal static int GetOffsetMask<T>()
5455
{
56+
#if NETCOREAPP3_0_OR_NEWER
57+
return InlineCalculateOffsetMask(Unsafe.SizeOf<T>());
58+
#else
5559
if (Unsafe.SizeOf<T>() == Unsafe.SizeOf<object>())
5660
{
5761
return ReferenceTypeSegmentHelper.OffsetMask;
@@ -60,6 +64,7 @@ internal static int GetOffsetMask<T>()
6064
{
6165
return ValueTypeSegmentHelper<T>.OffsetMask;
6266
}
67+
#endif
6368
}
6469

6570
/// <summary>
@@ -121,6 +126,31 @@ private static int CalculateOffsetMask(int segmentSize)
121126
return segmentSize - 1;
122127
}
123128

129+
// Faster inline implementation for NETCOREAPP to avoid static constructors and non-inlineable
130+
// generics with runtime lookups
131+
#if NETCOREAPP3_0_OR_NEWER
132+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
133+
private static int InlineCalculateSegmentSize(int elementSize)
134+
{
135+
return 1 << InlineCalculateSegmentShift(elementSize);
136+
}
137+
138+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
139+
private static int InlineCalculateSegmentShift(int elementSize)
140+
{
141+
// Default Large Object Heap size threshold
142+
// https://github.com/dotnet/runtime/blob/c9d69e38d0e54bea5d188593ef6c3b30139f3ab1/src/coreclr/src/gc/gc.h#L111
143+
const uint Threshold = 85000;
144+
return System.Numerics.BitOperations.Log2((uint)((Threshold / elementSize) - (2 * Unsafe.SizeOf<object>())));
145+
}
146+
147+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
148+
private static int InlineCalculateOffsetMask(int elementSize)
149+
{
150+
return InlineCalculateSegmentSize(elementSize) - 1;
151+
}
152+
#endif
153+
124154
internal static class TestAccessor
125155
{
126156
public static int CalculateSegmentSize(int elementSize)

src/Dependencies/Collections/SegmentedArray`1.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ namespace Microsoft.CodeAnalysis.Collections
3232
/// </remarks>
3333
private static int SegmentSize
3434
{
35-
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
3635
get
3736
{
3837
return SegmentedArrayHelper.GetSegmentSize<T>();
@@ -44,7 +43,6 @@ private static int SegmentSize
4443
/// </summary>
4544
private static int SegmentShift
4645
{
47-
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
4846
get
4947
{
5048
return SegmentedArrayHelper.GetSegmentShift<T>();
@@ -56,7 +54,6 @@ private static int SegmentShift
5654
/// </summary>
5755
private static int OffsetMask
5856
{
59-
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
6057
get
6158
{
6259
return SegmentedArrayHelper.GetOffsetMask<T>();
@@ -115,7 +112,7 @@ private SegmentedArray(int length, T[][] items)
115112

116113
public ref T this[int index]
117114
{
118-
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
115+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
119116
get
120117
{
121118
return ref _items[index >> SegmentShift][index & OffsetMask];

0 commit comments

Comments
 (0)