Skip to content

Commit f977881

Browse files
authored
Move Array.CreateInstance methods to shared CoreLib (#66025)
1 parent 6187fdf commit f977881

File tree

8 files changed

+166
-432
lines changed

8 files changed

+166
-432
lines changed

src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs

Lines changed: 1 addition & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -15,119 +15,8 @@ namespace System
1515
// IList<U> and IReadOnlyList<U>, where T : U dynamically. See the SZArrayHelper class for details.
1616
public abstract partial class Array : ICloneable, IList, IStructuralComparable, IStructuralEquatable
1717
{
18-
// Create instance will create an array
19-
[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
20-
public static unsafe Array CreateInstance(Type elementType, int length)
21-
{
22-
if (elementType is null)
23-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType);
24-
if (length < 0)
25-
ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum();
26-
27-
RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType;
28-
if (t == null)
29-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType);
30-
return InternalCreate((void*)t.TypeHandle.Value, 1, &length, null);
31-
}
32-
33-
public static unsafe Array CreateInstance(Type elementType, int length1, int length2)
34-
{
35-
if (elementType is null)
36-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType);
37-
if (length1 < 0)
38-
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
39-
if (length2 < 0)
40-
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
41-
42-
RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType;
43-
if (t == null)
44-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType);
45-
int* pLengths = stackalloc int[2];
46-
pLengths[0] = length1;
47-
pLengths[1] = length2;
48-
return InternalCreate((void*)t.TypeHandle.Value, 2, pLengths, null);
49-
}
50-
51-
public static unsafe Array CreateInstance(Type elementType, int length1, int length2, int length3)
52-
{
53-
if (elementType is null)
54-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType);
55-
if (length1 < 0)
56-
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length1, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
57-
if (length2 < 0)
58-
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length2, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
59-
if (length3 < 0)
60-
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length3, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
61-
62-
RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType;
63-
if (t == null)
64-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType);
65-
int* pLengths = stackalloc int[3];
66-
pLengths[0] = length1;
67-
pLengths[1] = length2;
68-
pLengths[2] = length3;
69-
return InternalCreate((void*)t.TypeHandle.Value, 3, pLengths, null);
70-
}
71-
72-
[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
73-
public static unsafe Array CreateInstance(Type elementType, params int[] lengths)
74-
{
75-
if (elementType is null)
76-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType);
77-
if (lengths == null)
78-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths);
79-
if (lengths.Length == 0)
80-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank);
81-
82-
RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType;
83-
if (t == null)
84-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType);
85-
86-
// Check to make sure the lengths are all positive. Note that we check this here to give
87-
// a good exception message if they are not; however we check this again inside the execution
88-
// engine's low level allocation function after having made a copy of the array to prevent a
89-
// malicious caller from mutating the array after this check.
90-
for (int i = 0; i < lengths.Length; i++)
91-
if (lengths[i] < 0)
92-
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
93-
94-
fixed (int* pLengths = &lengths[0])
95-
return InternalCreate((void*)t.TypeHandle.Value, lengths.Length, pLengths, null);
96-
}
97-
98-
[RequiresDynamicCode("The code for an array of the specified type might not be available.")]
99-
public static unsafe Array CreateInstance(Type elementType, int[] lengths, int[] lowerBounds)
100-
{
101-
if (elementType == null)
102-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.elementType);
103-
if (lengths == null)
104-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lengths);
105-
if (lowerBounds == null)
106-
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.lowerBounds);
107-
if (lengths.Length != lowerBounds!.Length)
108-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_RanksAndBounds);
109-
if (lengths.Length == 0)
110-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_NeedAtLeast1Rank);
111-
112-
RuntimeType? t = elementType.UnderlyingSystemType as RuntimeType;
113-
if (t == null)
114-
ThrowHelper.ThrowArgumentException(ExceptionResource.Arg_MustBeType, ExceptionArgument.elementType);
115-
116-
// Check to make sure the lenghts are all positive. Note that we check this here to give
117-
// a good exception message if they are not; however we check this again inside the execution
118-
// engine's low level allocation function after having made a copy of the array to prevent a
119-
// malicious caller from mutating the array after this check.
120-
for (int i = 0; i < lengths.Length; i++)
121-
if (lengths[i] < 0)
122-
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.lengths, i, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum);
123-
124-
fixed (int* pLengths = &lengths[0])
125-
fixed (int* pLowerBounds = &lowerBounds[0])
126-
return InternalCreate((void*)t.TypeHandle.Value, lengths.Length, pLengths, pLowerBounds);
127-
}
128-
12918
[MethodImpl(MethodImplOptions.InternalCall)]
130-
private static extern unsafe Array InternalCreate(void* elementType, int rank, int* pLengths, int* pLowerBounds);
19+
private static extern unsafe Array InternalCreate(RuntimeType elementType, int rank, int* pLengths, int* pLowerBounds);
13120

13221
// Copies length elements from sourceArray, starting at index 0, to
13322
// destinationArray, starting at index 0.

src/coreclr/classlibnative/bcltype/arraynative.cpp

Lines changed: 21 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -815,10 +815,9 @@ FCIMPLEND
815815
void ArrayNative::CheckElementType(TypeHandle elementType)
816816
{
817817
// Checks apply recursively for arrays of arrays etc.
818-
if (elementType.IsArray())
818+
while (elementType.IsArray())
819819
{
820-
CheckElementType(elementType.GetArrayElementTypeHandle());
821-
return;
820+
elementType = elementType.GetArrayElementTypeHandle();
822821
}
823822

824823
// Check for simple types first.
@@ -837,28 +836,16 @@ void ArrayNative::CheckElementType(TypeHandle elementType)
837836
// Check for Void.
838837
if (elementType.GetSignatureCorElementType() == ELEMENT_TYPE_VOID)
839838
COMPlusThrow(kNotSupportedException, W("NotSupported_VoidArray"));
840-
841-
// That's all the dangerous simple types we know, it must be OK.
842-
return;
843839
}
844-
845-
// ByRefs and generic type variables are never allowed.
846-
if (elementType.IsByRef() || elementType.IsGenericVariable())
847-
COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
848-
849-
// We can create pointers and function pointers, but it requires skip verification permission.
850-
CorElementType etType = elementType.GetSignatureCorElementType();
851-
if (etType == ELEMENT_TYPE_PTR || etType == ELEMENT_TYPE_FNPTR)
840+
else
852841
{
853-
return;
842+
// ByRefs and generic type variables are never allowed.
843+
if (elementType.IsByRef() || elementType.IsGenericVariable())
844+
COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
854845
}
855-
856-
// We shouldn't get here (it means we've encountered a new type of typehandle if we do).
857-
_ASSERTE(!"Shouldn't get here, unknown type handle type");
858-
COMPlusThrow(kNotSupportedException);
859846
}
860847

861-
FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 rank, INT32* pLengths, INT32* pLowerBounds)
848+
FCIMPL4(Object*, ArrayNative::CreateInstance, ReflectClassBaseObject* pElementTypeUNSAFE, INT32 rank, INT32* pLengths, INT32* pLowerBounds)
862849
{
863850
CONTRACTL {
864851
FCALL_CHECK;
@@ -868,13 +855,14 @@ FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 ran
868855
} CONTRACTL_END;
869856

870857
OBJECTREF pRet = NULL;
871-
TypeHandle elementType = TypeHandle::FromPtr(elementTypeHandle);
872858

873-
_ASSERTE(!elementType.IsNull());
859+
REFLECTCLASSBASEREF pElementType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pElementTypeUNSAFE);
874860

875861
// pLengths and pLowerBounds are pinned buffers. No need to protect them.
876-
HELPER_METHOD_FRAME_BEGIN_RET_0();
862+
HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(pElementType);
877863

864+
TypeHandle elementType(pElementType->GetType());
865+
878866
CheckElementType(elementType);
879867

880868
CorElementType CorType = elementType.GetSignatureCorElementType();
@@ -913,34 +901,28 @@ FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 ran
913901
// Find the Array class...
914902
TypeHandle typeHnd = ClassLoader::LoadArrayTypeThrowing(elementType, kind, rank);
915903

904+
_ASSERTE(rank < MAX_RANK); // Ensures that the stack buffer size allocations below won't overlow
905+
916906
DWORD boundsSize = 0;
917907
INT32* bounds;
918-
if (pLowerBounds != NULL) {
919-
if (!ClrSafeInt<DWORD>::multiply(rank, 2, boundsSize))
920-
COMPlusThrowOM();
921-
DWORD dwAllocaSize = 0;
922-
if (!ClrSafeInt<DWORD>::multiply(boundsSize, sizeof(INT32), dwAllocaSize))
923-
COMPlusThrowOM();
924-
925-
bounds = (INT32*) _alloca(dwAllocaSize);
908+
if (pLowerBounds != NULL)
909+
{
910+
boundsSize = 2 * rank;
911+
bounds = (INT32*) _alloca(boundsSize * sizeof(INT32));
926912

927913
for (int i=0;i<rank;i++) {
928914
bounds[2*i] = pLowerBounds[i];
929915
bounds[2*i+1] = pLengths[i];
930916
}
931917
}
932-
else {
918+
else
919+
{
933920
boundsSize = rank;
934-
935-
DWORD dwAllocaSize = 0;
936-
if (!ClrSafeInt<DWORD>::multiply(boundsSize, sizeof(INT32), dwAllocaSize))
937-
COMPlusThrowOM();
938-
939-
bounds = (INT32*) _alloca(dwAllocaSize);
921+
bounds = (INT32*) _alloca(boundsSize * sizeof(INT32));
940922

941923
// We need to create a private copy of pLengths to avoid holes caused
942924
// by caller mutating the array
943-
for (int i=0;i<rank;i++)
925+
for (int i=0; i < rank; i++)
944926
bounds[i] = pLengths[i];
945927
}
946928

src/coreclr/classlibnative/bcltype/arraynative.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,7 @@ class ArrayNative
3232
static FCDECL2(FC_BOOL_RET, IsSimpleCopy, ArrayBase* pSrc, ArrayBase* pDst);
3333
static FCDECL5(void, CopySlow, ArrayBase* pSrc, INT32 iSrcIndex, ArrayBase* pDst, INT32 iDstIndex, INT32 iLength);
3434

35-
// This method will create a new array of type type, with zero lower
36-
// bounds and rank.
37-
static FCDECL4(Object*, CreateInstance, void* elementTypeHandle, INT32 rank, INT32* pLengths, INT32* pBounds);
35+
static FCDECL4(Object*, CreateInstance, ReflectClassBaseObject* pElementTypeUNSAFE, INT32 rank, INT32* pLengths, INT32* pBounds);
3836

3937
// This method will return a TypedReference to the array element
4038
static FCDECL2(Object*, GetValue, ArrayBase* refThisUNSAFE, INT_PTR flattenedIndex);

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/Augments/RuntimeAugments.cs

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -143,42 +143,16 @@ public static unsafe Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArray
143143
{
144144
// We just checked above that all lower bounds are zero. In that case, we should actually allocate
145145
// a new SzArray instead.
146-
RuntimeTypeHandle elementTypeHandle = new RuntimeTypeHandle(typeHandleForArrayType.ToEETypePtr().ArrayElementType);
147-
int length = lengths[0];
148-
if (length < 0)
149-
throw new OverflowException(); // For compat: we need to throw OverflowException(): Array.CreateInstance throws ArgumentOutOfRangeException()
150-
return Array.CreateInstance(Type.GetTypeFromHandle(elementTypeHandle), length);
146+
Type elementType = Type.GetTypeFromHandle(new RuntimeTypeHandle(typeHandleForArrayType.ToEETypePtr().ArrayElementType));
147+
return RuntimeImports.RhNewArray(elementType.MakeArrayType().TypeHandle.ToEETypePtr(), lengths[0]);
151148
}
152149

153-
// Create a local copy of the lenghts that cannot be motified by the caller
154-
int* pLengths = stackalloc int[lengths.Length];
150+
// Create a local copy of the lengths that cannot be modified by the caller
151+
int* pImmutableLengths = stackalloc int[lengths.Length];
155152
for (int i = 0; i < lengths.Length; i++)
156-
pLengths[i] = lengths[i];
153+
pImmutableLengths[i] = lengths[i];
157154

158-
return Array.NewMultiDimArray(typeHandleForArrayType.ToEETypePtr(), pLengths, lengths.Length);
159-
}
160-
161-
//
162-
// Helper to create an array from a newobj instruction
163-
//
164-
public static unsafe Array NewObjArray(RuntimeTypeHandle typeHandleForArrayType, int[] arguments)
165-
{
166-
EETypePtr eeTypePtr = typeHandleForArrayType.ToEETypePtr();
167-
Debug.Assert(eeTypePtr.IsArray);
168-
169-
fixed (int* pArguments = arguments)
170-
{
171-
return ArrayHelpers.NewObjArray((IntPtr)eeTypePtr.ToPointer(), arguments.Length, pArguments);
172-
}
173-
}
174-
175-
public static ref byte GetSzArrayElementAddress(Array array, int index)
176-
{
177-
if ((uint)index >= (uint)array.Length)
178-
throw new IndexOutOfRangeException();
179-
180-
ref byte start = ref Unsafe.As<RawArrayData>(array).Data;
181-
return ref Unsafe.Add(ref start, (IntPtr)(nint)((nuint)index * array.ElementSize));
155+
return Array.NewMultiDimArray(typeHandleForArrayType.ToEETypePtr(), pImmutableLengths, lengths.Length);
182156
}
183157

184158
public static IntPtr GetAllocateObjectHelperForType(RuntimeTypeHandle type)

src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/Runtime/CompilerHelpers/ArrayHelpers.cs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,15 +64,8 @@ public static unsafe Array NewObjArray(IntPtr pEEType, int nDimensions, int* pDi
6464
{
6565
// Multidimensional array of rank 1 with 0 lower bounds gets actually allocated
6666
// as an SzArray. SzArray is castable to MdArray rank 1.
67-
int length = pDimensions[0];
68-
if (length < 0)
69-
{
70-
// Compat: we need to throw OverflowException. Array.CreateInstance would throw ArgumentOutOfRange
71-
throw new OverflowException();
72-
}
73-
74-
RuntimeTypeHandle elementTypeHandle = new RuntimeTypeHandle(eeType.ArrayElementType);
75-
return Array.CreateInstance(Type.GetTypeFromHandle(elementTypeHandle), length);
67+
Type elementType = Type.GetTypeFromHandle(new RuntimeTypeHandle(eeType.ArrayElementType));
68+
return RuntimeImports.RhNewArray(elementType.MakeArrayType().TypeHandle.ToEETypePtr(), pDimensions[0]);
7669
}
7770

7871
return Array.NewMultiDimArray(eeType, pDimensions, rank);

0 commit comments

Comments
 (0)