Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move Array.CreateInstance methods to shared CoreLib #66025

Merged
merged 1 commit into from
Mar 9, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 1 addition & 112 deletions src/coreclr/System.Private.CoreLib/src/System/Array.CoreCLR.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
60 changes: 21 additions & 39 deletions src/coreclr/classlibnative/bcltype/arraynative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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;
Expand All @@ -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());
jkotas marked this conversation as resolved.
Show resolved Hide resolved

CheckElementType(elementType);

CorElementType CorType = elementType.GetSignatureCorElementType();
Expand Down Expand Up @@ -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];
}

Expand Down
4 changes: 1 addition & 3 deletions src/coreclr/classlibnative/bcltype/arraynative.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,7 @@ class ArrayNative
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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,42 +143,16 @@ public static unsafe Array NewMultiDimArray(RuntimeTypeHandle typeHandleForArray
{
// 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];
jkotas marked this conversation as resolved.
Show resolved Hide resolved
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading