Move Array.CreateInstance methods to shared CoreLib (#66025)
authorJan Kotas <jkotas@microsoft.com>
Wed, 9 Mar 2022 15:56:10 +0000 (07:56 -0800)
committerGitHub <noreply@github.com>
Wed, 9 Mar 2022 15:56:10 +0000 (07:56 -0800)
src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
src/coreclr/classlibnative/bcltype/arraynative.cpp
src/coreclr/classlibnative/bcltype/arraynative.h
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs
src/coreclr/nativeaot/System.Private.CoreLib/src/System/Array.CoreRT.cs
src/libraries/System.Private.CoreLib/src/System/Array.cs
src/mono/System.Private.CoreLib/src/System/Array.Mono.cs

index 2a9e861..5538d58 100644 (file)
@@ -15,119 +15,8 @@ namespace System
     // IList<U> and IReadOnlyList<U>, 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.
index ca60fa9..dfa1b33 100644 (file)
@@ -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<DWORD>::multiply(rank, 2, boundsSize))
-                COMPlusThrowOM();
-            DWORD dwAllocaSize = 0;
-            if (!ClrSafeInt<DWORD>::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<rank;i++) {
                 bounds[2*i] = pLowerBounds[i];
                 bounds[2*i+1] = pLengths[i];
             }
         }
-        else {
+        else
+        {
             boundsSize = rank;
-
-            DWORD dwAllocaSize = 0;
-            if (!ClrSafeInt<DWORD>::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<rank;i++)
+            for (int i=0; i < rank; i++)
                 bounds[i] = pLengths[i];
         }
 
index bd74be3..4fcd941 100644 (file)
@@ -32,9 +32,7 @@ public:
     static FCDECL2(FC_BOOL_RET, IsSimpleCopy, ArrayBase* pSrc, ArrayBase* pDst);
     static FCDECL5(void, CopySlow, ArrayBase* pSrc, INT32 iSrcIndex, ArrayBase* pDst, INT32 iDstIndex, INT32 iLength);
 
-    // This method will create a new array of type type, with zero lower
-    // bounds and rank.
-    static FCDECL4(Object*, CreateInstance, void* elementTypeHandle, INT32 rank, INT32* pLengths, INT32* pBounds);
+    static FCDECL4(Object*, CreateInstance, ReflectClassBaseObject* pElementTypeUNSAFE, INT32 rank, INT32* pLengths, INT32* pBounds);
 
     // This method will return a TypedReference to the array element
     static FCDECL2(Object*, GetValue, ArrayBase* refThisUNSAFE, INT_PTR flattenedIndex);
index 1981723..a52e040 100644 (file)
@@ -143,42 +143,16 @@ namespace Internal.Runtime.Augments
             {
                 // We just checked above that all lower bounds are zero. In that case, we should actually allocate
                 // a new SzArray instead.
-                RuntimeTypeHandle elementTypeHandle = new RuntimeTypeHandle(typeHandleForArrayType.ToEETypePtr().ArrayElementType);
-                int length = lengths[0];
-                if (length < 0)
-                    throw new OverflowException(); // For compat: we need to throw OverflowException(): Array.CreateInstance throws ArgumentOutOfRangeException()
-                return Array.CreateInstance(Type.GetTypeFromHandle(elementTypeHandle), length);
+                Type elementType = Type.GetTypeFromHandle(new RuntimeTypeHandle(typeHandleForArrayType.ToEETypePtr().ArrayElementType));
+                return RuntimeImports.RhNewArray(elementType.MakeArrayType().TypeHandle.ToEETypePtr(), lengths[0]);
             }
 
-            // Create a local copy of the lenghts that cannot be motified by the caller
-            int* pLengths = stackalloc int[lengths.Length];
+            // Create a local copy of the lengths that cannot be modified by the caller
+            int* pImmutableLengths = stackalloc int[lengths.Length];
             for (int i = 0; i < lengths.Length; i++)
-                pLengths[i] = lengths[i];
+                pImmutableLengths[i] = lengths[i];
 
-            return Array.NewMultiDimArray(typeHandleForArrayType.ToEETypePtr(), pLengths, lengths.Length);
-        }
-
-        //
-        // Helper to create an array from a newobj instruction
-        //
-        public static unsafe Array NewObjArray(RuntimeTypeHandle typeHandleForArrayType, int[] arguments)
-        {
-            EETypePtr eeTypePtr = typeHandleForArrayType.ToEETypePtr();
-            Debug.Assert(eeTypePtr.IsArray);
-
-            fixed (int* pArguments = arguments)
-            {
-                return ArrayHelpers.NewObjArray((IntPtr)eeTypePtr.ToPointer(), arguments.Length, pArguments);
-            }
-        }
-
-        public static ref byte GetSzArrayElementAddress(Array array, int index)
-        {
-            if ((uint)index >= (uint)array.Length)
-                throw new IndexOutOfRangeException();
-
-            ref byte start = ref Unsafe.As<RawArrayData>(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)
index 35e2dd5..1d60b8e 100644 (file)
@@ -64,15 +64,8 @@ namespace Internal.Runtime.CompilerHelpers
                 {
                     // 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);
index 8957c37..3fa434b 100644 (file)
@@ -64,144 +64,37 @@ namespace System
         }
 
         [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()!;
index 371705f..663d5f9 100644 (file)
@@ -68,6 +68,118 @@ namespace System
         }
 
         [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)
         {
             if (lengths == null)
index e774619..b51834e 100644 (file)
@@ -282,123 +282,16 @@ namespace System
             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<int> indices)
         {