You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Inconsistent inlining between Span.ToArray and ReadOnlySpan.ToArray #119713
These numbers do not seem to account for the code size of the non-inlined method.
Also, I assume that the code size improvements would be even better if the method is not split. Is that right? I do not see why we would want to pay extra code bloat to optimize ToArray() on empty Span.
The way I see it, the useful case is when the span is known to be non-empty, since the JIT can then get rid of the static constructor for Array.Empty<T>. So it's a way of having the JIT inline everything in that case without using AggressiveInlining.
The special casing for items.IsEmpty should not be needed in this case. I think we should delete it. Span.ToArray takes care of special casing the empty array already.
In the case of ImmutableArray, we also target .NET Framework, so this may well be written this way for a reason. If not, there doesn’t seem to be any reason to use ImmutableArray<T>.Empty rather than new ImmutableArray<T>(new T[0]) internally.
I doubt it. For reference, this was introduced in #61196. .NET Framework Span is very slow, there is no point in trying to optimize for it.
there doesn’t seem to be any reason to use ImmutableArray.Empty rather than new ImmutableArray(new T[0]) internally.
ImmutableArray.Empty is a singleton. It avoids GC heap allocation. The same optimization is in .NET Framework Span.
There is also Create() that is wrapper around ImmutableArray.Empty. There is no reason to use Create() internally - it is just an extra overhead. You can replace all Create() with ImmutableArray.Empty if you are going to submit a PR for this.
I think the special casing avoids an extra generic instantiation for Array.Empty<T>() in Span<T>.ToArray. Perhaps this explains the significant code size improvement in MihuBot/runtime-utils#2119
Activity
dotnet-policy-service commentedon Sep 15, 2025
Tagging subscribers to this area: @dotnet/area-system-runtime
See info in area-owners.md if you want to be subscribed.
xtqqczze commentedon Sep 15, 2025
Inlining seems beneficial if the span length is known to be non-zero, as the static ctor for
Array.Empty<T>()can then be elided.xtqqczze commentedon Sep 15, 2025
Some nice code size improvements by removing
AggressiveInliningand splitting the implementation across two methods: MihuBot/runtime-utils#1497jeffhandley commentedon Aug 17, 2026
Marked as help wanted, inviting a thorough analysis of the tradeoffs.
xtqqczze commentedon Aug 17, 2026
Code size improvement is even better now: MihuBot/runtime-utils#2119
jkotas commentedon Aug 17, 2026
These numbers do not seem to account for the code size of the non-inlined method.
Also, I assume that the code size improvements would be even better if the method is not split. Is that right? I do not see why we would want to pay extra code bloat to optimize ToArray() on empty Span.
xtqqczze commentedon Aug 17, 2026
The way I see it, the useful case is when the span is known to be non-empty, since the JIT can then get rid of the static constructor for
Array.Empty<T>. So it's a way of having the JIT inline everything in that case without usingAggressiveInlining.Let’s see anyway: MihuBot/runtime-utils#2120, MihuBot/runtime-utils#2121.
jkotas commentedon Aug 17, 2026
How common is that with ToArray?
MihaZupan commentedon Aug 17, 2026
Note that this is not an apples-apples comparison since the default MihuBot job is now also testing against a small subset of NuGet packages
xtqqczze commentedon Aug 17, 2026
Not that uncommon, here's an example:
runtime/src/libraries/System.Collections.Immutable/src/System/Collections/Immutable/ImmutableArray.cs
Lines 91 to 100 in 45ad194
jkotas commentedon Aug 17, 2026
The special casing for
items.IsEmptyshould not be needed in this case. I think we should delete it. Span.ToArray takes care of special casing the empty array already.xtqqczze commentedon Aug 17, 2026
In the case of
ImmutableArray, we also target .NET Framework, so this may well be written this way for a reason. If not, there doesn’t seem to be any reason to useImmutableArray<T>.Emptyrather thannew ImmutableArray<T>(new T[0])internally.jkotas commentedon Aug 17, 2026
I doubt it. For reference, this was introduced in #61196. .NET Framework Span is very slow, there is no point in trying to optimize for it.
ImmutableArray.Empty is a singleton. It avoids GC heap allocation. The same optimization is in .NET Framework Span.
There is also Create() that is wrapper around ImmutableArray.Empty. There is no reason to use Create() internally - it is just an extra overhead. You can replace all Create() with ImmutableArray.Empty if you are going to submit a PR for this.
xtqqczze commentedon Aug 17, 2026
I think the special casing avoids an extra generic instantiation for
Array.Empty<T>()inSpan<T>.ToArray. Perhaps this explains the significant code size improvement in MihuBot/runtime-utils#2119Remove forced inlining from Span<T>.ToArray (#132635)