Skip to content

Commit

Permalink
Simplify RuntimeHelpers.GetSubArray (#66011)
Browse files Browse the repository at this point in the history
The special casing of co-variant arrays was added in the original safe implementation to avoid exceptions from AsSpan (dotnet/coreclr#22331 (comment)). ArrayTypeMismatchException is no longer a concern with the new unsafe implementation. There is a subtle behavior change in the actual type for co-variant arrays of reference types. However, the new behavior matches Array.Resize and it is very unlikely for any code out there to depend on this co-variant arrays corner case.
  • Loading branch information
jkotas authored Mar 2, 2022
1 parent b11689b commit ca3c95b
Showing 1 changed file with 8 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,18 @@ public static T[] GetSubArray<T>(T[] array, Range range)

(int offset, int length) = range.GetOffsetAndLength(array.Length);

T[] dest;

if (typeof(T).IsValueType || typeof(T[]) == array.GetType())
if (length == 0)
{
// We know the type of the array to be exactly T[] or an array variance
// compatible value type substitution like int[] <-> uint[].

if (length == 0)
{
return Array.Empty<T>();
}

dest = new T[length];
return Array.Empty<T>();
}
else
{
// The array is actually a U[] where U:T. We'll make sure to create
// an array of the exact same backing type. The cast to T[] will
// never fail.

dest = Unsafe.As<T[]>(Array.CreateInstance(array.GetType().GetElementType()!, length));
}
T[] dest = new T[length];

// In either case, the newly-allocated array is the exact same type as the
// original incoming array. It's safe for us to Buffer.Memmove the contents
// from the source array to the destination array, otherwise the contents
// wouldn't have been valid for the source array in the first place.
// Due to array variance, it's possible that the incoming array is
// actually of type U[], where U:T; or that an int[] <-> uint[] or
// similar cast has occurred. In any case, since it's always legal
// to reinterpret U as T in this scenario (but not necessarily the
// other way around), we can use Buffer.Memmove here.

Buffer.Memmove(
ref MemoryMarshal.GetArrayDataReference(dest),
Expand Down

0 comments on commit ca3c95b

Please sign in to comment.