# HG changeset patch
# User igerasim
# Date 1557546883 25200
# Fri May 10 20:54:43 2019 -0700
# Node ID 27b7098787ba059f98cb693bfd05d460ce56d475
# Parent ad757676262c50fbb74790da778b3891e71b7fc6
[mq]: 8223593-Refactor-code-for-reallocating-storage
diff --git a/src/java.base/share/classes/java/io/BufferedInputStream.java b/src/java.base/share/classes/java/io/BufferedInputStream.java
--- a/src/java.base/share/classes/java/io/BufferedInputStream.java
+++ b/src/java.base/share/classes/java/io/BufferedInputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, 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
@@ -26,6 +26,7 @@
package java.io;
import jdk.internal.misc.Unsafe;
+import jdk.internal.util.ArraysSupport;
/**
* A BufferedInputStream
adds
@@ -54,14 +55,6 @@
private static int DEFAULT_BUFFER_SIZE = 8192;
/**
- * 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 int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;
-
- /**
* As this class is used early during bootstrap, it's motivated to use
* Unsafe.compareAndSetObject instead of AtomicReferenceFieldUpdater
* (or VarHandles) to reduce dependencies and improve startup time.
@@ -220,7 +213,7 @@
byte[] buffer = getBufIfOpen();
if (markpos < 0)
pos = 0; /* no mark: throw away the buffer */
- else if (pos >= buffer.length) /* no room left in buffer */
+ else if (pos >= buffer.length) { /* no room left in buffer */
if (markpos > 0) { /* can throw away early part of the buffer */
int sz = pos - markpos;
System.arraycopy(buffer, markpos, buffer, 0, sz);
@@ -229,11 +222,8 @@
} else if (buffer.length >= marklimit) {
markpos = -1; /* buffer got too big, invalidate mark */
pos = 0; /* drop buffer contents */
- } else if (buffer.length >= MAX_BUFFER_SIZE) {
- throw new OutOfMemoryError("Required array size too large");
} else { /* grow buffer */
- int nsz = (pos <= MAX_BUFFER_SIZE - pos) ?
- pos * 2 : MAX_BUFFER_SIZE;
+ int nsz = ArraysSupport.newCapacity(pos, 1, pos);
if (nsz > marklimit)
nsz = marklimit;
byte[] nbuf = new byte[nsz];
@@ -248,6 +238,7 @@
}
buffer = nbuf;
}
+ }
count = pos;
int n = getInIfOpen().read(buffer, pos, buffer.length - pos);
if (n > 0)
diff --git a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
--- a/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
+++ b/src/java.base/share/classes/java/io/ByteArrayOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, 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
@@ -29,6 +29,8 @@
import java.util.Arrays;
import java.util.Objects;
+import jdk.internal.util.ArraysSupport;
+
/**
* This class implements an output stream in which the data is
* written into a byte array. The buffer automatically grows as data
@@ -84,48 +86,20 @@
* at least the number of elements specified by the minimum
* capacity argument.
*
- * @param minCapacity the desired minimum capacity
- * @throws OutOfMemoryError if {@code minCapacity < 0}. This is
- * interpreted as a request for the unsatisfiably large capacity
+ * @param minCapacity the desired minimum capacity.
+ * @throws OutOfMemoryError if {@code minCapacity < 0} and
+ * {@code minCapacity - buf.length > 0}. This is interpreted as a
+ * request for the unsatisfiably large capacity.
* {@code (long) Integer.MAX_VALUE + (minCapacity - Integer.MAX_VALUE)}.
*/
private void ensureCapacity(int minCapacity) {
// overflow-conscious code
- if (minCapacity - buf.length > 0)
- grow(minCapacity);
- }
-
- /**
- * 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;
-
- /**
- * Increases the capacity to ensure that it can hold at least the
- * number of elements specified by the minimum capacity argument.
- *
- * @param minCapacity the desired minimum capacity
- */
- private void grow(int minCapacity) {
- // overflow-conscious code
int oldCapacity = buf.length;
- int newCapacity = oldCapacity << 1;
- if (newCapacity - minCapacity < 0)
- newCapacity = minCapacity;
- if (newCapacity - MAX_ARRAY_SIZE > 0)
- newCapacity = hugeCapacity(minCapacity);
- buf = Arrays.copyOf(buf, newCapacity);
- }
-
- private static int hugeCapacity(int minCapacity) {
- if (minCapacity < 0) // overflow
- throw new OutOfMemoryError();
- return (minCapacity > MAX_ARRAY_SIZE) ?
- Integer.MAX_VALUE :
- MAX_ARRAY_SIZE;
+ int growAtLeastBy = minCapacity - oldCapacity;
+ if (growAtLeastBy > 0) {
+ buf = Arrays.copyOf(buf, ArraysSupport.newCapacity(oldCapacity,
+ growAtLeastBy, oldCapacity));
+ }
}
/**
diff --git a/src/java.base/share/classes/java/lang/StringLatin1.java b/src/java.base/share/classes/java/lang/StringLatin1.java
--- a/src/java.base/share/classes/java/lang/StringLatin1.java
+++ b/src/java.base/share/classes/java/lang/StringLatin1.java
@@ -35,6 +35,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.util.ArraysSupport;
import static java.lang.String.LATIN1;
import static java.lang.String.UTF16;
@@ -42,14 +43,6 @@
final class StringLatin1 {
- /**
- * The maximum size of array to allocate (unless necessary).
- * 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;
-
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
@@ -353,15 +346,8 @@
i += targLen;
while ((j = indexOf(value, valLen, targ, targLen, i)) > 0) {
if (++p == pos.length) {
- int cap = p + (p >> 1);
- // overflow-conscious code
- if (cap - MAX_ARRAY_SIZE > 0) {
- if (p == MAX_ARRAY_SIZE) {
- throw new OutOfMemoryError();
- }
- cap = MAX_ARRAY_SIZE;
- }
- pos = Arrays.copyOf(pos, cap);
+ pos = Arrays.copyOf(pos, ArraysSupport.newCapacity(pos.length,
+ 1, p >> 1));
}
pos[p] = j;
i = j + targLen;
diff --git a/src/java.base/share/classes/java/lang/StringUTF16.java b/src/java.base/share/classes/java/lang/StringUTF16.java
--- a/src/java.base/share/classes/java/lang/StringUTF16.java
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java
@@ -33,6 +33,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.HotSpotIntrinsicCandidate;
+import jdk.internal.util.ArraysSupport;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.DontInline;
@@ -649,15 +650,8 @@
: indexOf(value, valLen, targ, targLen, i))) > 0)
{
if (++p == pos.length) {
- int cap = p + (p >> 1);
- // overflow-conscious code
- if (cap - MAX_ARRAY_SIZE > 0) {
- if (p == MAX_ARRAY_SIZE) {
- throw new OutOfMemoryError();
- }
- cap = MAX_ARRAY_SIZE;
- }
- pos = Arrays.copyOf(pos, cap);
+ pos = Arrays.copyOf(pos, ArraysSupport.newCapacity(pos.length,
+ 1, p >> 1));
}
pos[p] = j;
i = j + targLen;
@@ -1554,15 +1548,6 @@
static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
-
- /**
- * The maximum size of array to allocate (unless necessary).
- * 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;
-
// Used by trusted callers. Assumes all necessary bounds checks have
// been done by the caller.
diff --git a/src/java.base/share/classes/java/nio/file/Files.java b/src/java.base/share/classes/java/nio/file/Files.java
--- a/src/java.base/share/classes/java/nio/file/Files.java
+++ b/src/java.base/share/classes/java/nio/file/Files.java
@@ -77,6 +77,7 @@
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
+import jdk.internal.util.ArraysSupport;
import sun.nio.ch.FileChannelImpl;
import sun.nio.fs.AbstractFileSystemProvider;
@@ -3196,14 +3197,6 @@
}
}
- /**
- * 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_BUFFER_SIZE = Integer.MAX_VALUE - 8;
-
private static final jdk.internal.access.JavaLangAccess JLA =
jdk.internal.access.SharedSecrets.getJavaLangAccess();
@@ -3240,13 +3233,8 @@
break;
// one more byte was read; need to allocate a larger buffer
- if (capacity <= MAX_BUFFER_SIZE - capacity) {
- capacity = Math.max(capacity << 1, BUFFER_SIZE);
- } else {
- if (capacity == MAX_BUFFER_SIZE)
- throw new OutOfMemoryError("Required array size too large");
- capacity = MAX_BUFFER_SIZE;
- }
+ capacity = Math.max(ArraysSupport.newCapacity(capacity, 1, capacity),
+ BUFFER_SIZE);
buf = Arrays.copyOf(buf, capacity);
buf[nread++] = (byte)n;
}
@@ -3283,7 +3271,7 @@
if (sbc instanceof FileChannelImpl)
((FileChannelImpl) sbc).setUninterruptible();
long size = sbc.size();
- if (size > (long) MAX_BUFFER_SIZE)
+ if (size > (long) Integer.MAX_VALUE)
throw new OutOfMemoryError("Required array size too large");
return read(in, (int)size);
}
diff --git a/src/java.base/share/classes/java/util/AbstractCollection.java b/src/java.base/share/classes/java/util/AbstractCollection.java
--- a/src/java.base/share/classes/java/util/AbstractCollection.java
+++ b/src/java.base/share/classes/java/util/AbstractCollection.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, 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
@@ -25,6 +25,8 @@
package java.util;
+import jdk.internal.util.ArraysSupport;
+
/**
* This class provides a skeletal implementation of the {@code Collection}
* interface, to minimize the effort required to implement this interface.
@@ -204,14 +206,6 @@
}
/**
- * 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;
-
- /**
* Reallocates the array being used within toArray when the iterator
* returned more elements than expected, and finishes filling it from
* the iterator.
@@ -223,29 +217,17 @@
*/
@SuppressWarnings("unchecked")
private static Array equality and lexicographical comparison can be built on top of
* array mismatch functionality.
@@ -571,4 +573,49 @@
return -1;
}
+
+ /**
+ * The maximum size of array to allocate (unless necessary).
+ * Some VMs reserve some header words in an array.
+ * Attempts to allocate larger arrays may result in
+ * OutOfMemoryError: Requested array size exceeds VM limit
+ */
+ public static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
+
+ /**
+ * Calculates new size of an array to be reallocated.
+ *
+ * The result will be at least {@code X = oldCapacity + growAtLeastBy}.
+ * The result can be greater (normally, up to
+ * {@code oldCapacity + preferredGrowBy}).
+ * This function will not return values greater than
+ * {@link #MAX_ARRAY_SIZE} unless the minimum required size
+ * {@code X} is greater.
+ *
+ * @param oldCapacity current size of the array (must be non negative)
+ * @param growAtLeastBy minimum required growth of the array size (must
+ be positive)
+ * @param preferredGrowBy preferred growth of the array size
+ * @return the new size of the array
+ * @throws OutOfMemoryError if increasing {@code oldCapacity) by
+ * {@code growAtLeastBy} overflows.
+ */
+ public static int newCapacity(int oldCapacity,
+ int growAtLeastBy,
+ int preferredGrowBy) {
+ // assert oldCapacity >= 0
+ // assert growAtLeastBy > 0
+
+ int newCapacity = oldCapacity + Math.max(growAtLeastBy, preferredGrowBy);
+ return (newCapacity - MAX_ARRAY_SIZE > 0)
+ ? hugeCapacity(oldCapacity + growAtLeastBy) : newCapacity;
+ }
+
+ private static int hugeCapacity(int minCapacity) {
+ if (minCapacity < 0) { // overflow
+ throw new OutOfMemoryError("Required array size too large");
+ }
+ return (minCapacity > MAX_ARRAY_SIZE)
+ ? Integer.MAX_VALUE : MAX_ARRAY_SIZE;
+ }
}