Skip to content

Commit

Permalink
Optimize some SegmentedArrayHelper members for JIT (#67558)
Browse files Browse the repository at this point in the history
  • Loading branch information
EgorBo authored Apr 21, 2023
1 parent 75ab617 commit 94abcab
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 14 deletions.
50 changes: 40 additions & 10 deletions src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,12 @@ internal static class SegmentedArrayHelper
// Large value types may benefit from a smaller number.
internal const int IntrosortSizeThreshold = 16;

/// <summary>
/// A combination of <see cref="MethodImplOptions.AggressiveInlining"/> and
/// <see cref="F:System.Runtime.CompilerServices.MethodImplOptions.AggressiveOptimization"/>.
/// </summary>
[SuppressMessage("Documentation", "CA1200:Avoid using cref tags with a prefix", Justification = "The field is not supported in all compilation targets.")]
internal const MethodImplOptions FastPathMethodImplOptions = MethodImplOptions.AggressiveInlining | (MethodImplOptions)512;

[MethodImpl(FastPathMethodImplOptions)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetSegmentSize<T>()
{
#if NETCOREAPP3_0_OR_NEWER
return InlineCalculateSegmentSize(Unsafe.SizeOf<T>());
#else
if (Unsafe.SizeOf<T>() == Unsafe.SizeOf<object>())
{
return ReferenceTypeSegmentHelper.SegmentSize;
Expand All @@ -34,11 +30,15 @@ internal static int GetSegmentSize<T>()
{
return ValueTypeSegmentHelper<T>.SegmentSize;
}
#endif
}

[MethodImpl(FastPathMethodImplOptions)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetSegmentShift<T>()
{
#if NETCOREAPP3_0_OR_NEWER
return InlineCalculateSegmentShift(Unsafe.SizeOf<T>());
#else
if (Unsafe.SizeOf<T>() == Unsafe.SizeOf<object>())
{
return ReferenceTypeSegmentHelper.SegmentShift;
Expand All @@ -47,11 +47,15 @@ internal static int GetSegmentShift<T>()
{
return ValueTypeSegmentHelper<T>.SegmentShift;
}
#endif
}

[MethodImpl(FastPathMethodImplOptions)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetOffsetMask<T>()
{
#if NETCOREAPP3_0_OR_NEWER
return InlineCalculateOffsetMask(Unsafe.SizeOf<T>());
#else
if (Unsafe.SizeOf<T>() == Unsafe.SizeOf<object>())
{
return ReferenceTypeSegmentHelper.OffsetMask;
Expand All @@ -60,6 +64,7 @@ internal static int GetOffsetMask<T>()
{
return ValueTypeSegmentHelper<T>.OffsetMask;
}
#endif
}

/// <summary>
Expand Down Expand Up @@ -121,6 +126,31 @@ private static int CalculateOffsetMask(int segmentSize)
return segmentSize - 1;
}

// Faster inline implementation for NETCOREAPP to avoid static constructors and non-inlineable
// generics with runtime lookups
#if NETCOREAPP3_0_OR_NEWER
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int InlineCalculateSegmentSize(int elementSize)
{
return 1 << InlineCalculateSegmentShift(elementSize);
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int InlineCalculateSegmentShift(int elementSize)
{
// Default Large Object Heap size threshold
// https://github.com/dotnet/runtime/blob/c9d69e38d0e54bea5d188593ef6c3b30139f3ab1/src/coreclr/src/gc/gc.h#L111
const uint Threshold = 85000;
return System.Numerics.BitOperations.Log2((uint)((Threshold / elementSize) - (2 * Unsafe.SizeOf<object>())));
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static int InlineCalculateOffsetMask(int elementSize)
{
return InlineCalculateSegmentSize(elementSize) - 1;
}
#endif

internal static class TestAccessor
{
public static int CalculateSegmentSize(int elementSize)
Expand Down
5 changes: 1 addition & 4 deletions src/Dependencies/Collections/SegmentedArray`1.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ namespace Microsoft.CodeAnalysis.Collections
/// </remarks>
private static int SegmentSize
{
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
get
{
return SegmentedArrayHelper.GetSegmentSize<T>();
Expand All @@ -44,7 +43,6 @@ private static int SegmentSize
/// </summary>
private static int SegmentShift
{
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
get
{
return SegmentedArrayHelper.GetSegmentShift<T>();
Expand All @@ -56,7 +54,6 @@ private static int SegmentShift
/// </summary>
private static int OffsetMask
{
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
get
{
return SegmentedArrayHelper.GetOffsetMask<T>();
Expand Down Expand Up @@ -115,7 +112,7 @@ private SegmentedArray(int length, T[][] items)

public ref T this[int index]
{
[MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return ref _items[index >> SegmentShift][index & OffsetMask];
Expand Down

0 comments on commit 94abcab

Please sign in to comment.