diff options
author | Jan Kotas <jkotas@microsoft.com> | 2018-05-24 07:07:20 -0700 |
---|---|---|
committer | Jan Kotas <jkotas@microsoft.com> | 2018-06-27 06:14:47 -0700 |
commit | 2b283f380dac7834421a5dd979fdcc0b6e898607 (patch) | |
tree | 9861450cc1698d45dabe6d2481ec50a9d9c3eaa0 | |
parent | 9c6b90e42840050fec597cef53ae7d88695bf678 (diff) | |
download | coreclr-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
-rw-r--r-- | src/classlibnative/bcltype/arraynative.cpp | 41 | ||||
-rw-r--r-- | src/classlibnative/bcltype/arraynative.h | 3 | ||||
-rw-r--r-- | src/mscorlib/src/System/Array.cs | 31 | ||||
-rw-r--r-- | src/vm/ecalllist.h | 2 |
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) |