mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 02:24:40 +02:00
8247373: ArraysSupport.newLength doc, test, and exception message
Reviewed-by: rriggs, psandoz, martin, prappo
This commit is contained in:
parent
96c43210d3
commit
f18c019287
4 changed files with 169 additions and 36 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -575,52 +575,83 @@ public class ArraysSupport {
|
|||
}
|
||||
|
||||
/**
|
||||
* The maximum length of array to allocate (unless necessary).
|
||||
* Some VMs reserve some header words in an array.
|
||||
* Attempts to allocate larger arrays may result in
|
||||
* {@code OutOfMemoryError: Requested array size exceeds VM limit}
|
||||
* A soft maximum array length imposed by array growth computations.
|
||||
* Some JVMs (such as HotSpot) have an implementation limit that will cause
|
||||
*
|
||||
* OutOfMemoryError("Requested array size exceeds VM limit")
|
||||
*
|
||||
* to be thrown if a request is made to allocate an array of some length near
|
||||
* Integer.MAX_VALUE, even if there is sufficient heap available. The actual
|
||||
* limit might depend on some JVM implementation-specific characteristics such
|
||||
* as the object header size. The soft maximum value is chosen conservatively so
|
||||
* as to be smaller than any implementation limit that is likely to be encountered.
|
||||
*/
|
||||
public static final int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
|
||||
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
|
||||
|
||||
/**
|
||||
* Calculates a new array length given an array's current length, a preferred
|
||||
* growth value, and a minimum growth value. If the preferred growth value
|
||||
* is less than the minimum growth value, the minimum growth value is used in
|
||||
* its place. If the sum of the current length and the preferred growth
|
||||
* value does not exceed {@link #MAX_ARRAY_LENGTH}, that sum is returned.
|
||||
* If the sum of the current length and the minimum growth value does not
|
||||
* exceed {@code MAX_ARRAY_LENGTH}, then {@code MAX_ARRAY_LENGTH} is returned.
|
||||
* If the sum does not overflow an int, then {@code Integer.MAX_VALUE} is
|
||||
* returned. Otherwise, {@code OutOfMemoryError} is thrown.
|
||||
* Computes a new array length given an array's current length, a minimum growth
|
||||
* amount, and a preferred growth amount. The computation is done in an overflow-safe
|
||||
* fashion.
|
||||
*
|
||||
* @param oldLength current length of the array (must be non negative)
|
||||
* @param minGrowth minimum required growth of the array length (must be
|
||||
* positive)
|
||||
* @param prefGrowth preferred growth of the array length (ignored, if less
|
||||
* then {@code minGrowth})
|
||||
* @return the new length of the array
|
||||
* @throws OutOfMemoryError if increasing {@code oldLength} by
|
||||
* {@code minGrowth} overflows.
|
||||
* This method is used by objects that contain an array that might need to be grown
|
||||
* in order to fulfill some immediate need (the minimum growth amount) but would also
|
||||
* like to request more space (the preferred growth amount) in order to accommodate
|
||||
* potential future needs. The returned length is usually clamped at the soft maximum
|
||||
* length in order to avoid hitting the JVM implementation limit. However, the soft
|
||||
* maximum will be exceeded if the minimum growth amount requires it.
|
||||
*
|
||||
* If the preferred growth amount is less than the minimum growth amount, the
|
||||
* minimum growth amount is used as the preferred growth amount.
|
||||
*
|
||||
* The preferred length is determined by adding the preferred growth amount to the
|
||||
* current length. If the preferred length does not exceed the soft maximum length
|
||||
* (SOFT_MAX_ARRAY_LENGTH) then the preferred length is returned.
|
||||
*
|
||||
* If the preferred length exceeds the soft maximum, we use the minimum growth
|
||||
* amount. The minimum required length is determined by adding the minimum growth
|
||||
* amount to the current length. If the minimum required length exceeds Integer.MAX_VALUE,
|
||||
* then this method throws OutOfMemoryError. Otherwise, this method returns the greater of
|
||||
* the soft maximum or the minimum required length.
|
||||
*
|
||||
* Note that this method does not do any array allocation itself; it only does array
|
||||
* length growth computations. However, it will throw OutOfMemoryError as noted above.
|
||||
*
|
||||
* Note also that this method cannot detect the JVM's implementation limit, and it
|
||||
* may compute and return a length value up to and including Integer.MAX_VALUE that
|
||||
* might exceed the JVM's implementation limit. In that case, the caller will likely
|
||||
* attempt an array allocation with that length and encounter an OutOfMemoryError.
|
||||
* Of course, regardless of the length value returned from this method, the caller
|
||||
* may encounter OutOfMemoryError if there is insufficient heap to fulfill the request.
|
||||
*
|
||||
* @param oldLength current length of the array (must be nonnegative)
|
||||
* @param minGrowth minimum required growth amount (must be positive)
|
||||
* @param prefGrowth preferred growth amount
|
||||
* @return the new array length
|
||||
* @throws OutOfMemoryError if the new length would exceed Integer.MAX_VALUE
|
||||
*/
|
||||
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
|
||||
// preconditions not checked because of inlining
|
||||
// assert oldLength >= 0
|
||||
// assert minGrowth > 0
|
||||
|
||||
int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
|
||||
if (newLength - MAX_ARRAY_LENGTH <= 0) {
|
||||
return newLength;
|
||||
int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
|
||||
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
|
||||
return prefLength;
|
||||
} else {
|
||||
// put code cold in a separate method
|
||||
return hugeLength(oldLength, minGrowth);
|
||||
}
|
||||
return hugeLength(oldLength, minGrowth);
|
||||
}
|
||||
|
||||
private static int hugeLength(int oldLength, int minGrowth) {
|
||||
int minLength = oldLength + minGrowth;
|
||||
if (minLength < 0) { // overflow
|
||||
throw new OutOfMemoryError("Required array length too large");
|
||||
throw new OutOfMemoryError(
|
||||
"Required array length " + oldLength + " + " + minGrowth + " is too large");
|
||||
} else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {
|
||||
return SOFT_MAX_ARRAY_LENGTH;
|
||||
} else {
|
||||
return minLength;
|
||||
}
|
||||
if (minLength <= MAX_ARRAY_LENGTH) {
|
||||
return MAX_ARRAY_LENGTH;
|
||||
}
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue