diff --git a/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs b/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs
index da94baee92d68..df82f53ae1552 100644
--- a/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs
+++ b/src/Dependencies/Collections/Internal/SegmentedArrayHelper.cs
@@ -16,16 +16,12 @@ internal static class SegmentedArrayHelper
// Large value types may benefit from a smaller number.
internal const int IntrosortSizeThreshold = 16;
- ///
- /// A combination of and
- /// .
- ///
- [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()
{
+#if NETCOREAPP3_0_OR_NEWER
+ return InlineCalculateSegmentSize(Unsafe.SizeOf());
+#else
if (Unsafe.SizeOf() == Unsafe.SizeOf())
{
return ReferenceTypeSegmentHelper.SegmentSize;
@@ -34,11 +30,15 @@ internal static int GetSegmentSize()
{
return ValueTypeSegmentHelper.SegmentSize;
}
+#endif
}
- [MethodImpl(FastPathMethodImplOptions)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetSegmentShift()
{
+#if NETCOREAPP3_0_OR_NEWER
+ return InlineCalculateSegmentShift(Unsafe.SizeOf());
+#else
if (Unsafe.SizeOf() == Unsafe.SizeOf())
{
return ReferenceTypeSegmentHelper.SegmentShift;
@@ -47,11 +47,15 @@ internal static int GetSegmentShift()
{
return ValueTypeSegmentHelper.SegmentShift;
}
+#endif
}
- [MethodImpl(FastPathMethodImplOptions)]
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int GetOffsetMask()
{
+#if NETCOREAPP3_0_OR_NEWER
+ return InlineCalculateOffsetMask(Unsafe.SizeOf());
+#else
if (Unsafe.SizeOf() == Unsafe.SizeOf())
{
return ReferenceTypeSegmentHelper.OffsetMask;
@@ -60,6 +64,7 @@ internal static int GetOffsetMask()
{
return ValueTypeSegmentHelper.OffsetMask;
}
+#endif
}
///
@@ -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())));
+ }
+
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ private static int InlineCalculateOffsetMask(int elementSize)
+ {
+ return InlineCalculateSegmentSize(elementSize) - 1;
+ }
+#endif
+
internal static class TestAccessor
{
public static int CalculateSegmentSize(int elementSize)
diff --git a/src/Dependencies/Collections/SegmentedArray`1.cs b/src/Dependencies/Collections/SegmentedArray`1.cs
index 7805fea208ef3..9bb6c32dc5384 100644
--- a/src/Dependencies/Collections/SegmentedArray`1.cs
+++ b/src/Dependencies/Collections/SegmentedArray`1.cs
@@ -32,7 +32,6 @@ namespace Microsoft.CodeAnalysis.Collections
///
private static int SegmentSize
{
- [MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
get
{
return SegmentedArrayHelper.GetSegmentSize();
@@ -44,7 +43,6 @@ private static int SegmentSize
///
private static int SegmentShift
{
- [MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
get
{
return SegmentedArrayHelper.GetSegmentShift();
@@ -56,7 +54,6 @@ private static int SegmentShift
///
private static int OffsetMask
{
- [MethodImpl(SegmentedArrayHelper.FastPathMethodImplOptions)]
get
{
return SegmentedArrayHelper.GetOffsetMask();
@@ -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];