summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJan Kotas <jkotas@microsoft.com>2018-05-24 07:07:20 -0700
committerJan Kotas <jkotas@microsoft.com>2018-06-27 06:14:47 -0700
commit2b283f380dac7834421a5dd979fdcc0b6e898607 (patch)
tree9861450cc1698d45dabe6d2481ec50a9d9c3eaa0 /src
parent9c6b90e42840050fec597cef53ae7d88695bf678 (diff)
downloadcoreclr-2b283f380dac7834421a5dd979fdcc0b6e898607.tar.gz
coreclr-2b283f380dac7834421a5dd979fdcc0b6e898607.tar.bz2
coreclr-2b283f380dac7834421a5dd979fdcc0b6e898607.zip
Optimize Array.Clear using SpanHelpers (#18101)
Reimplement most of Array.Clear in managed code using Span Clear helpers. Fixes dotnet/corefx#29848
Diffstat (limited to 'src')
-rw-r--r--src/classlibnative/bcltype/arraynative.cpp41
-rw-r--r--src/classlibnative/bcltype/arraynative.h3
-rw-r--r--src/mscorlib/src/System/Array.cs31
-rw-r--r--src/vm/ecalllist.h2
4 files changed, 41 insertions, 36 deletions
diff --git a/src/classlibnative/bcltype/arraynative.cpp b/src/classlibnative/bcltype/arraynative.cpp
index b813b71638..d05f0ca1fb 100644
--- a/src/classlibnative/bcltype/arraynative.cpp
+++ b/src/classlibnative/bcltype/arraynative.cpp
@@ -1070,48 +1070,25 @@ FCIMPL6(void, ArrayNative::ArrayCopy, ArrayBase* m_pSrc, INT32 m_iSrcIndex, Arra
FCIMPLEND
-FCIMPL3(void, ArrayNative::ArrayClear, ArrayBase* pArrayUNSAFE, INT32 iIndex, INT32 iLength)
+FCIMPL5(void*, ArrayNative::GetRawArrayGeometry, ArrayBase* pArray, UINT32* pNumComponents, UINT32* pElementSize, INT32* pLowerBound, CLR_BOOL* pContainsGCPointers)
{
- FCALL_CONTRACT;
-
- BASEARRAYREF pArray = (BASEARRAYREF)pArrayUNSAFE;
-
- HELPER_METHOD_FRAME_BEGIN_1(pArray);
-
- // cannot pass null for array
- if (pArray == NULL)
- COMPlusThrowArgumentNull(W("array"), W("ArgumentNull_Array"));
-
- // array must be an array
- _ASSERTE(pArray->GetMethodTable()->IsArray());
-
- // array bounds checking
- int lb = pArray->GetLowerBoundsPtr()[0];
- if (iIndex < lb || (iIndex - lb) < 0 || iLength < 0)
- COMPlusThrow(kIndexOutOfRangeException);
+ VALIDATEOBJECT(pArray);
- if ((iIndex - lb) > (int)pArray->GetNumComponents() - iLength)
- COMPlusThrow(kIndexOutOfRangeException);
+ _ASSERTE(pArray != NULL);
- if (iLength > 0)
- {
- char* array = (char*)pArray->GetDataPtr();
-
- SIZE_T size = pArray->GetComponentSize();
- _ASSERTE(size >= 1);
+ MethodTable *pMT = pArray->GetMethodTable();
- ZeroMemoryInGCHeap(array + (iIndex - lb) * size, iLength * size);
- }
+ *pNumComponents = pArray->GetNumComponents();
+ *pElementSize = pMT->RawGetComponentSize();
+ *pLowerBound = pArray->GetLowerBoundsPtr()[0];
+ *pContainsGCPointers = !!pMT->ContainsPointers();
- HELPER_METHOD_FRAME_END();
+ return (BYTE*)pArray + ArrayBase::GetDataPtrOffset(pMT);
}
FCIMPLEND
-
-
-
// Check we're allowed to create an array with the given element type.
void ArrayNative::CheckElementType(TypeHandle elementType)
{
diff --git a/src/classlibnative/bcltype/arraynative.h b/src/classlibnative/bcltype/arraynative.h
index c742bc21a7..3b6d5495f3 100644
--- a/src/classlibnative/bcltype/arraynative.h
+++ b/src/classlibnative/bcltype/arraynative.h
@@ -35,7 +35,8 @@ public:
static FCDECL1(void, Initialize, ArrayBase* pArray);
static FCDECL6(void, ArrayCopy, ArrayBase* m_pSrc, INT32 m_iSrcIndex, ArrayBase* m_pDst, INT32 m_iDstIndex, INT32 m_iLength, CLR_BOOL reliable);
- static FCDECL3(void, ArrayClear, ArrayBase* pArrayUNSAFE, INT32 iIndex, INT32 iLength);
+
+ static FCDECL5(void*, GetRawArrayGeometry, ArrayBase* pArray, UINT32* pNumComponents, UINT32* pElementSize, INT32* pLowerBound, CLR_BOOL* pContainsGCPointers);
// This method will create a new array of type type, with zero lower
// bounds and rank.
diff --git a/src/mscorlib/src/System/Array.cs b/src/mscorlib/src/System/Array.cs
index 28a8d040c5..68bb8e84a8 100644
--- a/src/mscorlib/src/System/Array.cs
+++ b/src/mscorlib/src/System/Array.cs
@@ -21,6 +21,12 @@ using System.Runtime.Versioning;
using System.Security;
using Internal.Runtime.CompilerServices;
+#if BIT64
+using nuint = System.UInt64;
+#else
+using nuint = System.UInt32;
+#endif
+
namespace System
{
// Note that we make a T[] (single-dimensional w/ zero as the lower bound) implement both
@@ -265,8 +271,29 @@ namespace System
// Sets length elements in array to 0 (or null for Object arrays), starting
// at index.
//
- [MethodImplAttribute(MethodImplOptions.InternalCall)]
- public static extern void Clear(Array array, int index, int length);
+ public static unsafe void Clear(Array array, int index, int length)
+ {
+ if (array == null)
+ ThrowHelper.ThrowArgumentNullException(ExceptionArgument.array);
+
+ ref byte p = ref GetRawArrayGeometry(array, out uint numComponents, out uint elementSize, out int lowerBound, out bool containsGCPointers);
+
+ int offset = index - lowerBound;
+
+ if (index < lowerBound || offset < 0 || length < 0 || (uint)(offset + length) > numComponents)
+ ThrowHelper.ThrowIndexOutOfRangeException();
+
+ ref byte ptr = ref Unsafe.AddByteOffset(ref p, (uint)offset * (nuint)elementSize);
+ nuint byteLength = (uint)length * (nuint)elementSize;
+
+ if (containsGCPointers)
+ SpanHelpers.ClearWithReferences(ref Unsafe.As<byte, IntPtr>(ref ptr), byteLength / (uint)sizeof(IntPtr));
+ else
+ SpanHelpers.ClearWithoutReferences(ref ptr, byteLength);
+ }
+
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ private static extern ref byte GetRawArrayGeometry(Array array, out uint numComponents, out uint elementSize, out int lowerBound, out bool containsGCPointers);
// The various Get values...
public unsafe Object GetValue(params int[] indices)
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 998f62b908..677d39b706 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -810,7 +810,7 @@ FCFuncStart(gArrayFuncs)
FCFuncElement("GetDataPtrOffsetInternal", ArrayNative::GetDataPtrOffsetInternal)
FCFuncElement("Initialize", ArrayNative::Initialize)
FCFuncElement("Copy", ArrayNative::ArrayCopy)
- FCFuncElement("Clear", ArrayNative::ArrayClear)
+ FCFuncElement("GetRawArrayGeometry", ArrayNative::GetRawArrayGeometry)
FCFuncElement("InternalCreate", ArrayNative::CreateInstance)
FCFuncElement("InternalGetReference", ArrayNative::GetReference)
FCFuncElement("InternalSetValue", ArrayNative::SetValue)