Skip to content

Commit 15e02a1

Browse files
committed
Implement Array.MaxLength and fix all remaining references
1 parent 0bdd2f0 commit 15e02a1

File tree

27 files changed

+77
-98
lines changed

27 files changed

+77
-98
lines changed

src/coreclr/vm/gchelpers.cpp

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -342,13 +342,13 @@ void PublishObjectAndNotify(TObj* &orObject, GC_ALLOC_FLAGS flags)
342342
#endif // FEATURE_EVENT_TRACE
343343
}
344344

345-
inline SIZE_T MaxArrayLength(SIZE_T componentSize)
345+
inline SIZE_T MaxArrayLength()
346346
{
347347
// Impose limits on maximum array length in each dimension to allow efficient
348348
// implementation of advanced range check elimination in future. We have to allow
349349
// higher limit for array of bytes (or one byte structs) for backward compatibility.
350-
// Keep in sync with Array.MaxArrayLength in BCL.
351-
return (componentSize == 1) ? 0X7FFFFFC7 : 0X7FEFFFFF;
350+
// Keep in sync with Array.MaxLength in BCL.
351+
return 0X7FFFFFC7;
352352
}
353353

354354
OBJECTREF AllocateSzArray(TypeHandle arrayType, INT32 cElements, GC_ALLOC_FLAGS flags)
@@ -388,11 +388,11 @@ OBJECTREF AllocateSzArray(MethodTable* pArrayMT, INT32 cElements, GC_ALLOC_FLAGS
388388
if (cElements < 0)
389389
COMPlusThrow(kOverflowException);
390390

391-
SIZE_T componentSize = pArrayMT->GetComponentSize();
392-
if ((SIZE_T)cElements > MaxArrayLength(componentSize))
391+
if ((SIZE_T)cElements > MaxArrayLength())
393392
ThrowOutOfMemoryDimensionsExceeded();
394393

395394
// Allocate the space from the GC heap
395+
SIZE_T componentSize = pArrayMT->GetComponentSize();
396396
#ifdef TARGET_64BIT
397397
// POSITIVE_INT32 * UINT16 + SMALL_CONST
398398
// this cannot overflow on 64bit
@@ -568,7 +568,6 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
568568

569569
// Calculate the total number of elements in the array
570570
UINT32 cElements;
571-
SIZE_T componentSize = pArrayMT->GetComponentSize();
572571
bool maxArrayDimensionLengthOverflow = false;
573572
bool providedLowerBounds = false;
574573

@@ -599,7 +598,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
599598
int length = pArgs[i];
600599
if (length < 0)
601600
COMPlusThrow(kOverflowException);
602-
if ((SIZE_T)length > MaxArrayLength(componentSize))
601+
if ((SIZE_T)length > MaxArrayLength())
603602
maxArrayDimensionLengthOverflow = true;
604603
if ((length > 0) && (lowerBound + (length - 1) < lowerBound))
605604
COMPlusThrow(kArgumentOutOfRangeException, W("ArgumentOutOfRange_ArrayLBAndLength"));
@@ -615,7 +614,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
615614
int length = pArgs[0];
616615
if (length < 0)
617616
COMPlusThrow(kOverflowException);
618-
if ((SIZE_T)length > MaxArrayLength(componentSize))
617+
if ((SIZE_T)length > MaxArrayLength())
619618
maxArrayDimensionLengthOverflow = true;
620619
cElements = length;
621620
}
@@ -625,6 +624,7 @@ OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs,
625624
ThrowOutOfMemoryDimensionsExceeded();
626625

627626
// Allocate the space from the GC heap
627+
SIZE_T componentSize = pArrayMT->GetComponentSize();
628628
#ifdef TARGET_64BIT
629629
// POSITIVE_INT32 * UINT16 + SMALL_CONST
630630
// this cannot overflow on 64bit

src/libraries/Common/src/System/Buffers/ArrayBufferWriter.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ namespace System.Buffers
1515
#endif
1616
sealed class ArrayBufferWriter<T> : IBufferWriter<T>
1717
{
18-
// Copy of Array.MaxArrayLength. For byte arrays the limit is slightly larger
19-
private const int MaxArrayLength = 0X7FEFFFFF;
18+
// Copy of Array.MaxLength.
19+
private const int ArrayMaxLength = 0x7FFFFFC7;
2020

2121
private const int DefaultInitialBufferSize = 256;
2222

@@ -184,16 +184,16 @@ private void CheckAndResizeBuffer(int sizeHint)
184184

185185
if ((uint)newSize > int.MaxValue)
186186
{
187-
// Attempt to grow to MaxArrayLength.
187+
// Attempt to grow to ArrayMaxLength.
188188
uint needed = (uint)(currentLength - FreeCapacity + sizeHint);
189189
Debug.Assert(needed > currentLength);
190190

191-
if (needed > MaxArrayLength)
191+
if (needed > ArrayMaxLength)
192192
{
193193
ThrowOutOfMemoryException(needed);
194194
}
195195

196-
newSize = MaxArrayLength;
196+
newSize = ArrayMaxLength;
197197
}
198198

199199
Array.Resize(ref _buffer, newSize);

src/libraries/Common/src/System/Collections/Generic/ArrayBuilder.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,9 +143,9 @@ private void EnsureCapacity(int minimum)
143143
int capacity = Capacity;
144144
int nextCapacity = capacity == 0 ? DefaultCapacity : 2 * capacity;
145145

146-
if ((uint)nextCapacity > (uint)Array.GetMaxLength<T>())
146+
if ((uint)nextCapacity > (uint)Array.MaxLength)
147147
{
148-
nextCapacity = Math.Max(capacity + 1, Array.GetMaxLength<T>());
148+
nextCapacity = Math.Max(capacity + 1, Array.MaxLength);
149149
}
150150

151151
nextCapacity = Math.Max(nextCapacity, minimum);

src/libraries/Common/src/System/Collections/Generic/EnumerableHelpers.cs

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -53,17 +53,12 @@ internal static T[] ToArray<T>(IEnumerable<T> source, out int length)
5353
// If the array is currently empty, we make it a default size. Otherwise, we attempt to
5454
// double the size of the array. Doubling will overflow once the size of the array reaches
5555
// 2^30, since doubling to 2^31 is 1 larger than Int32.MaxValue. In that case, we instead
56-
// constrain the length to be MaxArrayLength (this overflow check works because of the
57-
// cast to uint). Because a slightly larger constant is used when T is one byte in size, we
58-
// could then end up in a situation where arr.Length is MaxArrayLength or slightly larger, such
59-
// that we constrain newLength to be MaxArrayLength but the needed number of elements is actually
60-
// larger than that. For that case, we then ensure that the newLength is large enough to hold
61-
// the desired capacity. This does mean that in the very rare case where we've grown to such a
62-
// large size, each new element added after MaxArrayLength will end up doing a resize.
56+
// constrain the length to be Array.MaxLength (this overflow check works because of the
57+
// cast to uint).
6358
int newLength = count << 1;
64-
if ((uint)newLength > Array.GetMaxLength<T>())
59+
if ((uint)newLength > Array.MaxLength)
6560
{
66-
newLength = Array.GetMaxLength<T>() <= count ? count + 1 : Array.GetMaxLength<T>();
61+
newLength = Array.MaxLength <= count ? count + 1 : Array.MaxLength;
6762
}
6863

6964
Array.Resize(ref arr, newLength);

src/libraries/System.Collections.Concurrent/src/System/Collections/Concurrent/ConcurrentDictionary.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,7 +1963,7 @@ private void GrowTable(Tables tables)
19631963

19641964
Debug.Assert(newLength % 2 != 0);
19651965

1966-
if (newLength > Array.GetMaxLength<object>())
1966+
if (newLength > Array.MaxLength)
19671967
{
19681968
maximizeTableSize = true;
19691969
}
@@ -1976,7 +1976,7 @@ private void GrowTable(Tables tables)
19761976

19771977
if (maximizeTableSize)
19781978
{
1979-
newLength = Array.GetMaxLength<object>();
1979+
newLength = Array.MaxLength;
19801980

19811981
// We want to make sure that GrowTable will not be called again, since table is at the maximum size.
19821982
// To achieve that, we set the budget to int.MaxValue.

src/libraries/System.Collections.NonGeneric/src/System/Collections/SortedList.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -375,7 +375,7 @@ private void EnsureCapacity(int min)
375375
int newCapacity = keys.Length == 0 ? 16 : keys.Length * 2;
376376
// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
377377
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
378-
if ((uint)newCapacity > Array.GetMaxLength<object>()) newCapacity = Array.GetMaxLength<object>();
378+
if ((uint)newCapacity > Array.MaxLength) newCapacity = Array.MaxLength;
379379
if (newCapacity < min) newCapacity = min;
380380
Capacity = newCapacity;
381381
}

src/libraries/System.Collections.NonGeneric/tests/SortedListTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ public void DebuggerAttribute_NullSortedList_ThrowsArgumentNullException()
255255
}
256256

257257
[Fact]
258-
public void EnsureCapacity_NewCapacityLessThanMin_CapsToMaxArrayLength()
258+
public void EnsureCapacity_NewCapacityLessThanMin_CapsToArrayMaxLength()
259259
{
260260
// A situation like this occurs for very large lengths of SortedList.
261261
// To avoid allocating several GBs of memory and making this test run for a very

src/libraries/System.Collections/src/System/Collections/Generic/PriorityQueue.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -529,22 +529,20 @@ private void Grow(int minCapacity)
529529
{
530530
Debug.Assert(_nodes.Length < minCapacity);
531531

532-
// Array.MaxArrayLength is internal to S.P.CoreLib, replicate here.
533-
const int MaxArrayLength = 0X7FEFFFFF;
534532
const int GrowFactor = 2;
535533
const int MinimumGrow = 4;
536534

537535
int newcapacity = GrowFactor * _nodes.Length;
538536

539537
// Allow the queue to grow to maximum possible capacity (~2G elements) before encountering overflow.
540538
// Note that this check works even when _nodes.Length overflowed thanks to the (uint) cast
541-
if ((uint)newcapacity > MaxArrayLength) newcapacity = MaxArrayLength;
539+
if ((uint)newcapacity > Array.MaxLength) newcapacity = Array.MaxLength;
542540

543541
// Ensure minimum growth is respected.
544542
newcapacity = Math.Max(newcapacity, _nodes.Length + MinimumGrow);
545543

546544
// If the computed capacity is still less than specified, set to the original argument.
547-
// Capacities exceeding MaxArrayLength will be surfaced as OutOfMemoryException by Array.Resize.
545+
// Capacities exceeding Array.MaxLength will be surfaced as OutOfMemoryException by Array.Resize.
548546
if (newcapacity < minCapacity) newcapacity = minCapacity;
549547

550548
Array.Resize(ref _nodes, newcapacity);

src/libraries/System.Collections/src/System/Collections/Generic/Queue.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -400,22 +400,20 @@ private void Grow(int capacity)
400400
{
401401
Debug.Assert(_array.Length < capacity);
402402

403-
// Array.MaxArrayLength is internal to S.P.CoreLib, replicate here.
404-
const int MaxArrayLength = 0X7FEFFFFF;
405403
const int GrowFactor = 2;
406404
const int MinimumGrow = 4;
407405

408406
int newcapacity = GrowFactor * _array.Length;
409407

410408
// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
411409
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
412-
if ((uint)newcapacity > MaxArrayLength) newcapacity = MaxArrayLength;
410+
if ((uint)newcapacity > Array.MaxLength) newcapacity = Array.MaxLength;
413411

414412
// Ensure minimum growth is respected.
415413
newcapacity = Math.Max(newcapacity, _array.Length + MinimumGrow);
416414

417415
// If the computed capacity is still less than specified, set to the original argument.
418-
// Capacities exceeding MaxArrayLength will be surfaced as OutOfMemoryException by Array.Resize.
416+
// Capacities exceeding Array.MaxLength will be surfaced as OutOfMemoryException by Array.Resize.
419417
if (newcapacity < capacity) newcapacity = capacity;
420418

421419
SetCapacity(newcapacity);

src/libraries/System.Collections/src/System/Collections/Generic/SortedList.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -530,7 +530,7 @@ private void EnsureCapacity(int min)
530530
int newCapacity = keys.Length == 0 ? DefaultCapacity : keys.Length * 2;
531531
// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
532532
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
533-
if ((uint)newCapacity > Array.GetMaxLength<object>()) newCapacity = Array.GetMaxLength<object>();
533+
if ((uint)newCapacity > Array.MaxLength) newCapacity = Array.MaxLength;
534534
if (newCapacity < min) newCapacity = min;
535535
Capacity = newCapacity;
536536
}

0 commit comments

Comments
 (0)