Skip to content

Commit

Permalink
Add internal Array.Clear method
Browse files Browse the repository at this point in the history
  • Loading branch information
GrabYourPitchforks committed Apr 21, 2021
1 parent 4baf7f0 commit 9b65c32
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 13 deletions.
22 changes: 22 additions & 0 deletions src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,28 @@ public static void ConstrainedCopy(Array sourceArray, int sourceIndex, Array des
Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length, reliable: true);
}

internal static unsafe void Clear(Array array)
{
if (array == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);

MethodTable* pMT = RuntimeHelpers.GetMethodTable(array);
nuint totalByteLength = pMT->ComponentSize * array.NativeLength;
ref byte pStart = ref array.GetRawArrayData();

if (!pMT->ContainsGCPointers)
{
SpanHelpers.ClearWithoutReferences(ref pStart, totalByteLength);
}
else
{
Debug.Assert(totalByteLength % (nuint)sizeof(IntPtr) == 0);
SpanHelpers.ClearWithReferences(ref Unsafe.As<byte, IntPtr>(ref pStart), totalByteLength / (nuint)sizeof(IntPtr));
}

// GC.KeepAlive(array) not required. pMT kept alive via `pStart`
}

// Sets length elements in array to 0 (or null for Object arrays), starting
// at index.
//
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Private.CoreLib/src/System/Array.cs
Original file line number Diff line number Diff line change
Expand Up @@ -355,7 +355,7 @@ bool IList.Contains(object? value)

void IList.Clear()
{
Array.Clear(this, this.GetLowerBound(0), this.Length);
Array.Clear(this);
}

int IList.IndexOf(object? value)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ public override void Return(T[] array, bool clearArray = false)
// Clear the array if the user requests
if (clearArray)
{
Array.Clear(array, 0, array.Length);
Array.Clear(array);
}

// Return the buffer to its bucket. In the future, we might consider having Return return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ public override void Return(T[] array, bool clearArray = false)
// Clear the array if the user requests.
if (clearArray)
{
Array.Clear(array, 0, array.Length);
Array.Clear(array);
}

// Check to see if the buffer is the correct size for this bucket
Expand Down Expand Up @@ -274,7 +274,7 @@ public bool Trim()
foreach (KeyValuePair<T[]?[], object?> tlsBuckets in s_allTlsBuckets)
{
T[]?[] buckets = tlsBuckets.Key;
Array.Clear(buckets, 0, buckets.Length);
Array.Clear(buckets);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ public void Clear()
Debug.Assert(_buckets != null, "_buckets should be non-null");
Debug.Assert(_entries != null, "_entries should be non-null");

Array.Clear(_buckets, 0, _buckets.Length);
Array.Clear(_buckets);

_count = 0;
_freeList = -1;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ public void Clear()
Debug.Assert(_buckets != null, "_buckets should be non-null");
Debug.Assert(_entries != null, "_entries should be non-null");

Array.Clear(_buckets, 0, _buckets.Length);
Array.Clear(_buckets);
_count = 0;
_freeList = -1;
_freeCount = 0;
Expand Down
37 changes: 30 additions & 7 deletions src/libraries/System.Runtime/tests/System/ArrayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4655,18 +4655,41 @@ public static void Copy_LargeMultiDimensionalArray()
return;
}

try
short[,] a = AllocateLargeMDArray(2, 2_000_000_000);
a[0, 1] = 42;
Array.Copy(a, 1, a, Int32.MaxValue, 2);
Assert.Equal(42, a[1, Int32.MaxValue - 2_000_000_000]);

Array.Clear(a, Int32.MaxValue - 1, 3);
Assert.Equal(0, a[1, Int32.MaxValue - 2_000_000_000]);
}

[OuterLoop] // Allocates large array
[ConditionalFact]
public static void Clear_LargeMultiDimensionalArray()
{
// If this test is run in a 32-bit process, the large allocation will fail.
if (IntPtr.Size != sizeof(long))
{
short[,] a = new short[2, 2_000_000_000];
a[0, 1] = 42;
Array.Copy(a, 1, a, Int32.MaxValue, 2);
Assert.Equal(42, a[1, Int32.MaxValue - 2_000_000_000]);
return;
}

short[,] a = AllocateLargeMDArray(2, 2_000_000_000);
a[1, 1_999_999_999] = 0x1234;

((IList)a).Clear();
Assert.Equal(0, a[1, 1_999_999_999]);
}

Array.Clear(a, Int32.MaxValue - 1, 3);
Assert.Equal(0, a[1, Int32.MaxValue - 2_000_000_000]);
private static short[,] AllocateLargeMDArray(int dim0Length, int dim1Length)
{
try
{
return new short[dim0Length, dim1Length];
}
catch (OutOfMemoryException)
{
// not a fatal error - we'll just skip the test in this case
throw new SkipTestException("Unable to allocate enough memory");
}
}
Expand Down
14 changes: 14 additions & 0 deletions src/mono/System.Private.CoreLib/src/System/Array.Mono.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ public int Rank
get => Rank;
}

internal static unsafe void Clear(Array array)
{
if (array == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);

ref byte ptr = ref array.GetRawSzArrayData();
nuint byteLength = array.NativeLength * (nuint)(uint)array.GetElementSize() /* force zero-extension */;

if (RuntimeHelpers.ObjectHasReferences(array))
SpanHelpers.ClearWithReferences(ref Unsafe.As<byte, IntPtr>(ref ptr), byteLength / (uint)sizeof(IntPtr));
else
SpanHelpers.ClearWithoutReferences(ref ptr, byteLength);
}

public static unsafe void Clear(Array array, int index, int length)
{
if (array == null)
Expand Down

0 comments on commit 9b65c32

Please sign in to comment.