diff --git a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java index d554294efd5..1fe8eabf3c8 100644 --- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java +++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java @@ -31,6 +31,7 @@ import java.util.Arrays; import java.util.Spliterator; import java.util.stream.IntStream; import java.util.stream.StreamSupport; +import jdk.internal.util.ArraysSupport; import static java.lang.String.COMPACT_STRINGS; import static java.lang.String.UTF16; @@ -239,7 +240,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * Returns a capacity at least as large as the given minimum capacity. - * Returns the current capacity increased by the same amount + 2 if + * Returns the current capacity increased by the current length + 2 if * that suffices. * Will not return a capacity greater than * {@code (MAX_ARRAY_SIZE >> coder)} unless the given minimum capacity @@ -250,26 +251,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence { * greater than (Integer.MAX_VALUE >> coder) */ private int newCapacity(int minCapacity) { - // overflow-conscious code - int oldCapacity = value.length >> coder; - int newCapacity = (oldCapacity << 1) + 2; - if (newCapacity - minCapacity < 0) { - newCapacity = minCapacity; + int oldLength = value.length; + int newLength = minCapacity << coder; + int growth = newLength - oldLength; + int length = ArraysSupport.newLength(oldLength, growth, oldLength + (2 << coder)); + if (length == Integer.MAX_VALUE) { + throw new OutOfMemoryError("Required length exceeds implementation limit"); } - int SAFE_BOUND = MAX_ARRAY_SIZE >> coder; - return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0) - ? hugeCapacity(minCapacity) - : newCapacity; - } - - private int hugeCapacity(int minCapacity) { - int SAFE_BOUND = MAX_ARRAY_SIZE >> coder; - int UNSAFE_BOUND = Integer.MAX_VALUE >> coder; - if (UNSAFE_BOUND - minCapacity < 0) { // overflow - throw new OutOfMemoryError(); - } - return (minCapacity > SAFE_BOUND) - ? minCapacity : SAFE_BOUND; + return length >> coder; } /** diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 7d89b7d5ff6..33992cad98e 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -2187,7 +2187,7 @@ public final class String resultLen = Math.addExact(thisLen, Math.multiplyExact( Math.addExact(thisLen, 1), replLen)); } catch (ArithmeticException ignored) { - throw new OutOfMemoryError(); + throw new OutOfMemoryError("Required length exceeds implementation limit"); } StringBuilder sb = new StringBuilder(resultLen); @@ -3571,15 +3571,14 @@ public final class String if (len == 0 || count == 0) { return ""; } + if (Integer.MAX_VALUE / count < len) { + throw new OutOfMemoryError("Required length exceeds implementation limit"); + } if (len == 1) { final byte[] single = new byte[count]; Arrays.fill(single, value[0]); return new String(single, coder); } - if (Integer.MAX_VALUE / count < len) { - throw new OutOfMemoryError("Repeating " + len + " bytes String " + count + - " times will produce a String exceeding maximum size."); - } final int limit = len * count; final byte[] multiple = new byte[limit]; System.arraycopy(value, 0, multiple, 0, len); diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java index ca558c27bec..5dabc4e92cd 100644 --- a/src/java.base/share/classes/java/lang/StringLatin1.java +++ b/src/java.base/share/classes/java/lang/StringLatin1.java @@ -357,7 +357,7 @@ final class StringLatin1 { resultLen = Math.addExact(valLen, Math.multiplyExact(++p, replLen - targLen)); } catch (ArithmeticException ignored) { - throw new OutOfMemoryError(); + throw new OutOfMemoryError("Required length exceeds implementation limit"); } if (resultLen == 0) { return ""; diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java index a923070a86f..cbf8193bbd9 100644 --- a/src/java.base/share/classes/java/lang/StringUTF16.java +++ b/src/java.base/share/classes/java/lang/StringUTF16.java @@ -661,7 +661,7 @@ final class StringUTF16 { resultLen = Math.addExact(valLen, Math.multiplyExact(++p, replLen - targLen)); } catch (ArithmeticException ignored) { - throw new OutOfMemoryError(); + throw new OutOfMemoryError("Required length exceeds implementation limit"); } if (resultLen == 0) { return ""; diff --git a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java index 7e184625915..80c5765111e 100644 --- a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java @@ -53,6 +53,7 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import java.util.function.Predicate; import jdk.internal.access.SharedSecrets; +import jdk.internal.util.ArraysSupport; /** * An unbounded {@linkplain BlockingQueue blocking queue} that uses @@ -136,14 +137,6 @@ public class PriorityBlockingQueue extends AbstractQueue */ private static final int DEFAULT_INITIAL_CAPACITY = 11; - /** - * The maximum size of array to allocate. - * Some VMs reserve some header words in an array. - * Attempts to allocate larger arrays may result in - * OutOfMemoryError: Requested array size exceeds VM limit - */ - private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; - /** * Priority queue represented as a balanced binary heap: the two * children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The @@ -298,16 +291,9 @@ public class PriorityBlockingQueue extends AbstractQueue if (allocationSpinLock == 0 && ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) { try { - int newCap = oldCap + ((oldCap < 64) ? - (oldCap + 2) : // grow faster if small - (oldCap >> 1)); - if (newCap - MAX_ARRAY_SIZE > 0) { // possible overflow - int minCap = oldCap + 1; - if (minCap < 0 || minCap > MAX_ARRAY_SIZE) - throw new OutOfMemoryError(); - newCap = MAX_ARRAY_SIZE; - } - if (newCap > oldCap && queue == array) + int growth = oldCap < 64 ? oldCap + 2 : oldCap >> 1; + int newCap = ArraysSupport.newLength(oldCap, 1, growth); + if (queue == array) newArray = new Object[newCap]; } finally { allocationSpinLock = 0; diff --git a/src/java.base/share/classes/java/util/regex/Pattern.java b/src/java.base/share/classes/java/util/regex/Pattern.java index 82325d04f25..25efbe89534 100644 --- a/src/java.base/share/classes/java/util/regex/Pattern.java +++ b/src/java.base/share/classes/java/util/regex/Pattern.java @@ -1681,7 +1681,7 @@ loop: for(int x=0, offset=0; x size) { @@ -58,7 +58,7 @@ public class UnsyncByteArrayOutputStream extends OutputStream { public void write(byte[] arg0, int arg1, int arg2) { if ((VM_ARRAY_INDEX_MAX_VALUE - pos) < arg2) { - throw new OutOfMemoryError(); + throw new OutOfMemoryError("Required length exceeds implementation limit"); } int newPos = pos + arg2; if (newPos > size) { @@ -70,7 +70,7 @@ public class UnsyncByteArrayOutputStream extends OutputStream { public void write(int arg0) { if (VM_ARRAY_INDEX_MAX_VALUE - pos == 0) { - throw new OutOfMemoryError(); + throw new OutOfMemoryError("Required length exceeds implementation limit"); } int newPos = pos + 1; if (newPos > size) { @@ -116,4 +116,4 @@ public class UnsyncByteArrayOutputStream extends OutputStream { buf = newBuf; size = newSize; } -} \ No newline at end of file +} diff --git a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ByteArrayChannel.java b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ByteArrayChannel.java index 84e122a835b..2ba7c1bd6de 100644 --- a/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ByteArrayChannel.java +++ b/src/jdk.zipfs/share/classes/jdk/nio/zipfs/ByteArrayChannel.java @@ -244,7 +244,7 @@ public class ByteArrayChannel implements SeekableByteChannel { private static int hugeCapacity(int minCapacity) { if (minCapacity < 0) // overflow - throw new OutOfMemoryError(); + throw new OutOfMemoryError("Required length exceeds implementation limit"); return (minCapacity > MAX_ARRAY_SIZE) ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;