From f97788194aa647bf46c3c1e3b0526704dce15093 Mon Sep 17 00:00:00 2001 From: Jan Kotas Date: Wed, 9 Mar 2022 07:56:10 -0800 Subject: [PATCH] Move Array.CreateInstance methods to shared CoreLib (#66025) --- .../src/System/Array.CoreCLR.cs | 113 +------------- .../classlibnative/bcltype/arraynative.cpp | 60 +++----- .../classlibnative/bcltype/arraynative.h | 4 +- .../Runtime/Augments/RuntimeAugments.cs | 38 +---- .../Runtime/CompilerHelpers/ArrayHelpers.cs | 11 +- .../src/System/Array.CoreRT.cs | 143 +++--------------- .../src/System/Array.cs | 112 ++++++++++++++ .../src/System/Array.Mono.cs | 117 +------------- 8 files changed, 166 insertions(+), 432 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs index 2a9e861a49d2c..5538d58e8d969 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs @@ -15,119 +15,8 @@ namespace System // IList and IReadOnlyList, where T : U dynamically. See the SZArrayHelper class for details. public abstract partial class Array : ICloneable, IList, IStructuralComparable, IStructuralEquatable { - // Create instance will create an array - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static unsafe Array CreateInstance(Type elementType, int length) - { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (length < 0) - ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - - RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; - if (t == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - return InternalCreate((void*)t.TypeHandle.Value, 1, &length, null); - } - - public static unsafe Array CreateInstance(Type elementType, int length1, int length2) - { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (length1 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - if (length2 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; - if (t == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - int* pLengths = stackalloc int[2]; - pLengths[0] = length1; - pLengths[1] = length2; - return InternalCreate((void*)t.TypeHandle.Value, 2, pLengths, null); - } - - public static unsafe Array CreateInstance(Type elementType, int length1, int length2, int length3) - { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (length1 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - if (length2 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - if (length3 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length3, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; - if (t == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - int* pLengths = stackalloc int[3]; - pLengths[0] = length1; - pLengths[1] = length2; - pLengths[2] = length3; - return InternalCreate((void*)t.TypeHandle.Value, 3, pLengths, null); - } - - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static unsafe Array CreateInstance(Type elementType, params int[] lengths) - { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (lengths == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths); - if (lengths.Length == 0) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank); - - RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; - if (t == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - - // Check to make sure the lengths are all positive. Note that we check this here to give - // a good exception message if they are not; however we check this again inside the execution - // engine's low level allocation function after having made a copy of the array to prevent a - // malicious caller from mutating the array after this check. - for (int i = 0; i < lengths.Length; i++) - if (lengths[i] < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - fixed (int* pLengths = &lengths[0]) - return InternalCreate((void*)t.TypeHandle.Value, lengths.Length, pLengths, null); - } - - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static unsafe Array CreateInstance(Type elementType, int[] lengths, int[] lowerBounds) - { - if (elementType == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (lengths == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths); - if (lowerBounds == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lowerBounds); - if (lengths.Length != lowerBounds!.Length) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RanksAndBounds); - if (lengths.Length == 0) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank); - - RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; - if (t == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - - // Check to make sure the lenghts are all positive. Note that we check this here to give - // a good exception message if they are not; however we check this again inside the execution - // engine's low level allocation function after having made a copy of the array to prevent a - // malicious caller from mutating the array after this check. - for (int i = 0; i < lengths.Length; i++) - if (lengths[i] < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - fixed (int* pLengths = &lengths[0]) - fixed (int* pLowerBounds = &lowerBounds[0]) - return InternalCreate((void*)t.TypeHandle.Value, lengths.Length, pLengths, pLowerBounds); - } - [MethodImpl(MethodImplOptions.InternalCall)] - private static extern unsafe Array InternalCreate(void* elementType, int rank, int* pLengths, int* pLowerBounds); + private static extern unsafe Array InternalCreate(RuntimeType elementType, int rank, int* pLengths, int* pLowerBounds); // Copies length elements from sourceArray, starting at index 0, to // destinationArray, starting at index 0. diff --git a/src/coreclr/classlibnative/bcltype/arraynative.cpp b/src/coreclr/classlibnative/bcltype/arraynative.cpp index ca60fa978a626..dfa1b33647407 100644 --- a/src/coreclr/classlibnative/bcltype/arraynative.cpp +++ b/src/coreclr/classlibnative/bcltype/arraynative.cpp @@ -815,10 +815,9 @@ FCIMPLEND void ArrayNative::CheckElementType(TypeHandle elementType) { // Checks apply recursively for arrays of arrays etc. - if (elementType.IsArray()) + while (elementType.IsArray()) { - CheckElementType(elementType.GetArrayElementTypeHandle()); - return; + elementType = elementType.GetArrayElementTypeHandle(); } // Check for simple types first. @@ -837,28 +836,16 @@ void ArrayNative::CheckElementType(TypeHandle elementType) // Check for Void. if (elementType.GetSignatureCorElementType() == ELEMENT_TYPE_VOID) COMPlusThrow(kNotSupportedException, W("NotSupported_VoidArray")); - - // That's all the dangerous simple types we know, it must be OK. - return; } - - // ByRefs and generic type variables are never allowed. - if (elementType.IsByRef() || elementType.IsGenericVariable()) - COMPlusThrow(kNotSupportedException, W("NotSupported_Type")); - - // We can create pointers and function pointers, but it requires skip verification permission. - CorElementType etType = elementType.GetSignatureCorElementType(); - if (etType == ELEMENT_TYPE_PTR || etType == ELEMENT_TYPE_FNPTR) + else { - return; + // ByRefs and generic type variables are never allowed. + if (elementType.IsByRef() || elementType.IsGenericVariable()) + COMPlusThrow(kNotSupportedException, W("NotSupported_Type")); } - - // We shouldn't get here (it means we've encountered a new type of typehandle if we do). - _ASSERTE(!"Shouldn't get here, unknown type handle type"); - COMPlusThrow(kNotSupportedException); } -FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 rank, INT32* pLengths, INT32* pLowerBounds) +FCIMPL4(Object*, ArrayNative::CreateInstance, ReflectClassBaseObject* pElementTypeUNSAFE, INT32 rank, INT32* pLengths, INT32* pLowerBounds) { CONTRACTL { FCALL_CHECK; @@ -868,13 +855,14 @@ FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 ran } CONTRACTL_END; OBJECTREF pRet = NULL; - TypeHandle elementType = TypeHandle::FromPtr(elementTypeHandle); - _ASSERTE(!elementType.IsNull()); + REFLECTCLASSBASEREF pElementType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pElementTypeUNSAFE); // pLengths and pLowerBounds are pinned buffers. No need to protect them. - HELPER_METHOD_FRAME_BEGIN_RET_0(); + HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(pElementType); + TypeHandle elementType(pElementType->GetType()); + CheckElementType(elementType); CorElementType CorType = elementType.GetSignatureCorElementType(); @@ -913,34 +901,28 @@ FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 ran // Find the Array class... TypeHandle typeHnd = ClassLoader::LoadArrayTypeThrowing(elementType, kind, rank); + _ASSERTE(rank < MAX_RANK); // Ensures that the stack buffer size allocations below won't overlow + DWORD boundsSize = 0; INT32* bounds; - if (pLowerBounds != NULL) { - if (!ClrSafeInt::multiply(rank, 2, boundsSize)) - COMPlusThrowOM(); - DWORD dwAllocaSize = 0; - if (!ClrSafeInt::multiply(boundsSize, sizeof(INT32), dwAllocaSize)) - COMPlusThrowOM(); - - bounds = (INT32*) _alloca(dwAllocaSize); + if (pLowerBounds != NULL) + { + boundsSize = 2 * rank; + bounds = (INT32*) _alloca(boundsSize * sizeof(INT32)); for (int i=0;i::multiply(boundsSize, sizeof(INT32), dwAllocaSize)) - COMPlusThrowOM(); - - bounds = (INT32*) _alloca(dwAllocaSize); + bounds = (INT32*) _alloca(boundsSize * sizeof(INT32)); // We need to create a private copy of pLengths to avoid holes caused // by caller mutating the array - for (int i=0;i= (uint)array.Length) - throw new IndexOutOfRangeException(); - - ref byte start = ref Unsafe.As(array).Data; - return ref Unsafe.Add(ref start, (IntPtr)(nint)((nuint)index * array.ElementSize)); + return Array.NewMultiDimArray(typeHandleForArrayType.ToEETypePtr(), pImmutableLengths, lengths.Length); } public static IntPtr GetAllocateObjectHelperForType(RuntimeTypeHandle type) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs index 35e2dd52cbc5c..1d60b8e6d1516 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs @@ -64,15 +64,8 @@ public static unsafe Array NewObjArray(IntPtr pEEType, int nDimensions, int* pDi { // Multidimensional array of rank 1 with 0 lower bounds gets actually allocated // as an SzArray. SzArray is castable to MdArray rank 1. - int length = pDimensions[0]; - if (length < 0) - { - // Compat: we need to throw OverflowException. Array.CreateInstance would throw ArgumentOutOfRange - throw new OverflowException(); - } - - RuntimeTypeHandle elementTypeHandle = new RuntimeTypeHandle(eeType.ArrayElementType); - return Array.CreateInstance(Type.GetTypeFromHandle(elementTypeHandle), length); + Type elementType = Type.GetTypeFromHandle(new RuntimeTypeHandle(eeType.ArrayElementType)); + return RuntimeImports.RhNewArray(elementType.MakeArrayType().TypeHandle.ToEETypePtr(), pDimensions[0]); } return Array.NewMultiDimArray(eeType, pDimensions, rank); diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.CoreRT.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.CoreRT.cs index 8957c3721385d..3fa434bc55b43 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.CoreRT.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.CoreRT.cs @@ -64,144 +64,37 @@ internal bool IsSzArray } [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static Array CreateInstance(Type elementType, int length) + private static unsafe Array InternalCreate(RuntimeType elementType, int rank, int* pLengths, int* pLowerBounds) { - if (elementType is null) - throw new ArgumentNullException(nameof(elementType)); - - return CreateSzArray(elementType, length); - } - - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", - Justification = "MDArrays of Rank != 1 can be created because they don't implement generic interfaces.")] - public static unsafe Array CreateInstance(Type elementType, int length1, int length2) - { - if (elementType is null) - throw new ArgumentNullException(nameof(elementType)); - if (length1 < 0) - throw new ArgumentOutOfRangeException(nameof(length1)); - if (length2 < 0) - throw new ArgumentOutOfRangeException(nameof(length2)); - - Type arrayType = GetArrayTypeFromElementType(elementType, true, 2); - int* pLengths = stackalloc int[2]; - pLengths[0] = length1; - pLengths[1] = length2; - return NewMultiDimArray(arrayType.TypeHandle.ToEETypePtr(), pLengths, 2); - } + ValidateElementType(elementType); - [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", - Justification = "MDArrays of Rank != 1 can be created because they don't implement generic interfaces.")] - public static unsafe Array CreateInstance(Type elementType, int length1, int length2, int length3) - { - if (elementType is null) - throw new ArgumentNullException(nameof(elementType)); - if (length1 < 0) - throw new ArgumentOutOfRangeException(nameof(length1)); - if (length2 < 0) - throw new ArgumentOutOfRangeException(nameof(length2)); - if (length3 < 0) - throw new ArgumentOutOfRangeException(nameof(length3)); - - Type arrayType = GetArrayTypeFromElementType(elementType, true, 3); - int* pLengths = stackalloc int[3]; - pLengths[0] = length1; - pLengths[1] = length2; - pLengths[2] = length3; - return NewMultiDimArray(arrayType.TypeHandle.ToEETypePtr(), pLengths, 3); - } + if (pLowerBounds != null) + { + for (int i = 0; i < rank; i++) + { + if (pLowerBounds[i] != 0) + throw new PlatformNotSupportedException(SR.PlatformNotSupported_NonZeroLowerBound); + } + } - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static Array CreateInstance(Type elementType, params int[] lengths) - { - if (elementType is null) - throw new ArgumentNullException(nameof(elementType)); - if (lengths is null) - throw new ArgumentNullException(nameof(lengths)); - if (lengths.Length == 0) - throw new ArgumentException(SR.Arg_NeedAtLeast1Rank); - - // Check to make sure the lengths are all positive. Note that we check this here to give - // a good exception message if they are not; however we check this again inside the execution - // engine's low level allocation function after having made a copy of the array to prevent a - // malicious caller from mutating the array after this check. - for (int i = 0; i < lengths.Length; i++) - if (lengths[i] < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - if (lengths.Length == 1) + if (rank == 1) { - int length = lengths[0]; - return CreateSzArray(elementType, length); + return RuntimeImports.RhNewArray(elementType.MakeArrayType().TypeHandle.ToEETypePtr(), pLengths[0]); + } else { - return CreateMultiDimArray(elementType, lengths, null); - } - } + // Create a local copy of the lenghts that cannot be motified by the caller + int* pImmutableLengths = stackalloc int[rank]; + for (int i = 0; i < rank; i++) + pImmutableLengths[i] = pLengths[i]; - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static Array CreateInstance(Type elementType, int[] lengths, int[] lowerBounds) - { - if (elementType is null) - throw new ArgumentNullException(nameof(elementType)); - if (lengths is null) - throw new ArgumentNullException(nameof(lengths)); - if (lowerBounds is null) - throw new ArgumentNullException(nameof(lowerBounds)); - if (lengths.Length != lowerBounds.Length) - throw new ArgumentException(SR.Arg_RanksAndBounds); - if (lengths.Length == 0) - throw new ArgumentException(SR.Arg_NeedAtLeast1Rank); - - return CreateMultiDimArray(elementType, lengths, lowerBounds); - } - - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - private static Array CreateSzArray(Type elementType, int length) - { - // Though our callers already validated length once, this parameter is passed via arrays, so we must check it again - // in case a malicious caller modified the array after the check. - if (length < 0) - throw new ArgumentOutOfRangeException(nameof(length)); - - Type arrayType = GetArrayTypeFromElementType(elementType, false, 1); - return RuntimeImports.RhNewArray(arrayType.TypeHandle.ToEETypePtr(), length); - } - - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - private static Array CreateMultiDimArray(Type elementType, int[] lengths, int[] lowerBounds) - { - Debug.Assert(lengths != null); - Debug.Assert(lowerBounds == null || lowerBounds.Length == lengths.Length); - - for (int i = 0; i < lengths.Length; i++) - { - if (lengths[i] < 0) - throw new ArgumentOutOfRangeException("lengths[" + i + "]", SR.ArgumentOutOfRange_NeedNonNegNum); + return NewMultiDimArray(elementType.MakeArrayType(rank).TypeHandle.ToEETypePtr(), pImmutableLengths, rank); } - - int rank = lengths.Length; - Type arrayType = GetArrayTypeFromElementType(elementType, true, rank); - return RuntimeAugments.NewMultiDimArray(arrayType.TypeHandle, lengths, lowerBounds); - } - - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - private static Type GetArrayTypeFromElementType(Type elementType, bool multiDim, int rank) - { - elementType = elementType.UnderlyingSystemType; - ValidateElementType(elementType); - - if (multiDim) - return elementType.MakeArrayType(rank); - else - return elementType.MakeArrayType(); } private static void ValidateElementType(Type elementType) { - if (elementType is not RuntimeType) - throw new ArgumentException(SR.Arg_MustBeType, nameof(elementType)); while (elementType.IsArray) { elementType = elementType.GetElementType()!; diff --git a/src/libraries/System.Private.CoreLib/src/System/Array.cs b/src/libraries/System.Private.CoreLib/src/System/Array.cs index 371705fc953c5..663d5f9ba4d7f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Array.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Array.cs @@ -67,6 +67,118 @@ ref MemoryMarshal.GetArrayDataReference(larray), Debug.Assert(array != null); } + [RequiresDynamicCode("The code for an array of the specified type might not be available.")] + public static unsafe Array CreateInstance(Type elementType, int length) + { + if (elementType is null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); + if (length < 0) + ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); + + RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; + if (t == null) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); + + return InternalCreate(t, 1, &length, null); + } + + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "MDArrays of Rank != 1 can be created because they don't implement generic interfaces.")] + public static unsafe Array CreateInstance(Type elementType, int length1, int length2) + { + if (elementType is null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); + if (length1 < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); + if (length2 < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); + + RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; + if (t == null) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); + + int* pLengths = stackalloc int[] { length1, length2 }; + return InternalCreate(t, 2, pLengths, null); + } + + [UnconditionalSuppressMessage("AotAnalysis", "IL3050:RequiresDynamicCode", + Justification = "MDArrays of Rank != 1 can be created because they don't implement generic interfaces.")] + public static unsafe Array CreateInstance(Type elementType, int length1, int length2, int length3) + { + if (elementType is null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); + if (length1 < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); + if (length2 < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); + if (length3 < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length3, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); + + RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; + if (t == null) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); + + int* pLengths = stackalloc int[3] { length1, length2, length3 }; + return InternalCreate(t, 3, pLengths, null); + } + + [RequiresDynamicCode("The code for an array of the specified type might not be available.")] + public static unsafe Array CreateInstance(Type elementType, params int[] lengths) + { + if (elementType is null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); + if (lengths == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths); + if (lengths.Length == 0) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank); + + RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; + if (t == null) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); + + // Check to make sure the lengths are all non-negative. Note that we check this here to give + // a good exception message if they are not; however we check this again inside the execution + // engine's low level allocation function after having made a copy of the array to prevent a + // malicious caller from mutating the array after this check. + for (int i = 0; i < lengths.Length; i++) + if (lengths[i] < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); + + fixed (int* pLengths = &lengths[0]) + return InternalCreate(t, lengths.Length, pLengths, null); + } + + [RequiresDynamicCode("The code for an array of the specified type might not be available.")] + public static unsafe Array CreateInstance(Type elementType, int[] lengths, int[] lowerBounds) + { + if (elementType == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); + if (lengths == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths); + if (lowerBounds == null) + ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lowerBounds); + if (lengths.Length != lowerBounds.Length) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RanksAndBounds); + if (lengths.Length == 0) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank); + + RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType; + if (t == null) + ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); + + // Check to make sure the lengths are all non-negative. Note that we check this here to give + // a good exception message if they are not; however we check this again inside the execution + // engine's low level allocation function after having made a copy of the array to prevent a + // malicious caller from mutating the array after this check. + for (int i = 0; i < lengths.Length; i++) + if (lengths[i] < 0) + ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); + + fixed (int* pLengths = &lengths[0]) + fixed (int* pLowerBounds = &lowerBounds[0]) + return InternalCreate(t, lengths.Length, pLengths, pLowerBounds); + } + [RequiresDynamicCode("The code for an array of the specified type might not be available.")] public static Array CreateInstance(Type elementType, params long[] lengths) { diff --git a/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs index e774619f5b498..b51834ea72477 100644 --- a/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Array.Mono.cs @@ -282,123 +282,16 @@ private static bool CanAssignArrayElement(Type source, Type target) return false; } - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static unsafe Array CreateInstance(Type elementType, int length) + private static unsafe Array InternalCreate(RuntimeType elementType, int rank, int* lengths, int* lowerBounds) { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (length < 0) - ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum(); - - RuntimeType? runtimeType = elementType.UnderlyingSystemType as RuntimeType; - if (runtimeType == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - - Array? array = null; - InternalCreate(ref array, runtimeType._impl.Value, 1, &length, null); - GC.KeepAlive(runtimeType); - return array; - } - - public static unsafe Array CreateInstance(Type elementType, int length1, int length2) - { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (length1 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - if (length2 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - RuntimeType? runtimeType = elementType.UnderlyingSystemType as RuntimeType; - if (runtimeType == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - - int* lengths = stackalloc int[] { length1, length2 }; - Array? array = null; - InternalCreate(ref array, runtimeType._impl.Value, 2, lengths, null); - GC.KeepAlive(runtimeType); - return array; - } - - public static unsafe Array CreateInstance(Type elementType, int length1, int length2, int length3) - { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (length1 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - if (length2 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - if (length3 < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length3, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - RuntimeType? runtimeType = elementType.UnderlyingSystemType as RuntimeType; - if (runtimeType == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - - int* lengths = stackalloc int[] { length1, length2, length3 }; - Array? array = null; - InternalCreate(ref array, runtimeType._impl.Value, 3, lengths, null); - GC.KeepAlive(runtimeType); - return array; - } - - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static unsafe Array CreateInstance(Type elementType, params int[] lengths) - { - if (elementType is null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (lengths == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths); - if (lengths.Length == 0) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank); - - RuntimeType? runtimeType = elementType.UnderlyingSystemType as RuntimeType; - if (runtimeType == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - - for (int i = 0; i < lengths.Length; i++) - if (lengths[i] < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - Array? array = null; - fixed (int* pLengths = &lengths[0]) - InternalCreate(ref array, runtimeType._impl.Value, lengths.Length, pLengths, null); - GC.KeepAlive(runtimeType); - return array; - } - - [RequiresDynamicCode("The code for an array of the specified type might not be available.")] - public static unsafe Array CreateInstance(Type elementType, int[] lengths, int[] lowerBounds) - { - if (elementType == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType); - if (lengths == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths); - if (lowerBounds == null) - ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lowerBounds); - if (lengths.Length != lowerBounds!.Length) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RanksAndBounds); - if (lengths.Length == 0) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank); - - for (int i = 0; i < lengths.Length; i++) - if (lengths[i] < 0) - ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); - - RuntimeType? runtimeType = elementType.UnderlyingSystemType as RuntimeType; - if (runtimeType == null) - ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType); - Array? array = null; - fixed (int* pLengths = &lengths[0]) - fixed (int* pLowerBounds = &lowerBounds[0]) - InternalCreate(ref array, runtimeType._impl.Value, lengths.Length, pLengths, pLowerBounds); - GC.KeepAlive(runtimeType); - return array; + InternalCreate(ref array, elementType._impl.Value, rank, lengths, lowerBounds); + GC.KeepAlive(elementType); + return array!; } [MethodImpl(MethodImplOptions.InternalCall)] - private static extern unsafe void InternalCreate([NotNull] ref Array? result, IntPtr elementType, int rank, int* lengths, int* lowerBounds); + private static extern unsafe void InternalCreate(ref Array? result, IntPtr elementType, int rank, int* lengths, int* lowerBounds); private unsafe nint GetFlattenedIndex(ReadOnlySpan indices) {