Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java
41159 views
1
/*
2
* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
package jdk.internal.util;
26
27
import jdk.internal.misc.Unsafe;
28
import jdk.internal.vm.annotation.IntrinsicCandidate;
29
30
/**
31
* Utility methods to work with arrays. This includes a set of methods
32
* to find a mismatch between two primitive arrays. Also included is
33
* a method to calculate the new length of an array to be reallocated.
34
*
35
* <p>Array equality and lexicographical comparison can be built on top of
36
* array mismatch functionality.
37
*
38
* <p>The mismatch method implementation, {@link #vectorizedMismatch}, leverages
39
* vector-based techniques to access and compare the contents of two arrays.
40
* The Java implementation uses {@code Unsafe.getLongUnaligned} to access the
41
* content of an array, thus access is supported on platforms that do not
42
* support unaligned access. For a byte[] array, 8 bytes (64 bits) can be
43
* accessed and compared as a unit rather than individually, which increases
44
* the performance when the method is compiled by the HotSpot VM. On supported
45
* platforms the mismatch implementation is intrinsified to leverage SIMD
46
* instructions. So for a byte[] array, 16 bytes (128 bits), 32 bytes
47
* (256 bits), and perhaps in the future even 64 bytes (512 bits), platform
48
* permitting, can be accessed and compared as a unit, which further increases
49
* the performance over the Java implementation.
50
*
51
* <p>None of the mismatch methods perform array bounds checks. It is the
52
* responsibility of the caller (direct or otherwise) to perform such checks
53
* before calling this method.
54
*/
55
public class ArraysSupport {
56
static final Unsafe U = Unsafe.getUnsafe();
57
58
private static final boolean BIG_ENDIAN = U.isBigEndian();
59
60
public static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE);
61
public static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE);
62
public static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE);
63
public static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE);
64
public static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE);
65
public static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE);
66
public static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE);
67
public static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE);
68
69
private static final int LOG2_BYTE_BIT_SIZE = exactLog2(Byte.SIZE);
70
71
private static int exactLog2(int scale) {
72
if ((scale & (scale - 1)) != 0)
73
throw new Error("data type scale not a power of two");
74
return Integer.numberOfTrailingZeros(scale);
75
}
76
77
private ArraysSupport() {}
78
79
/**
80
* Find the relative index of the first mismatching pair of elements in two
81
* primitive arrays of the same component type. Pairs of elements will be
82
* tested in order relative to given offsets into both arrays.
83
*
84
* <p>This method does not perform type checks or bounds checks. It is the
85
* responsibility of the caller to perform such checks before calling this
86
* method.
87
*
88
* <p>The given offsets, in bytes, need not be aligned according to the
89
* given log<sub>2</sub> size the array elements. More specifically, an
90
* offset modulus the size need not be zero.
91
*
92
* @param a the first array to be tested for mismatch, or {@code null} for
93
* direct memory access
94
* @param aOffset the relative offset, in bytes, from the base address of
95
* the first array to test from, otherwise if the first array is
96
* {@code null}, an absolute address pointing to the first element to test.
97
* @param b the second array to be tested for mismatch, or {@code null} for
98
* direct memory access
99
* @param bOffset the relative offset, in bytes, from the base address of
100
* the second array to test from, otherwise if the second array is
101
* {@code null}, an absolute address pointing to the first element to test.
102
* @param length the number of array elements to test
103
* @param log2ArrayIndexScale log<sub>2</sub> of the array index scale, that
104
* corresponds to the size, in bytes, of an array element.
105
* @return if a mismatch is found a relative index, between 0 (inclusive)
106
* and {@code length} (exclusive), of the first mismatching pair of elements
107
* in the two arrays. Otherwise, if a mismatch is not found the bitwise
108
* compliment of the number of remaining pairs of elements to be checked in
109
* the tail of the two arrays.
110
*/
111
@IntrinsicCandidate
112
public static int vectorizedMismatch(Object a, long aOffset,
113
Object b, long bOffset,
114
int length,
115
int log2ArrayIndexScale) {
116
// assert a.getClass().isArray();
117
// assert b.getClass().isArray();
118
// assert 0 <= length <= sizeOf(a)
119
// assert 0 <= length <= sizeOf(b)
120
// assert 0 <= log2ArrayIndexScale <= 3
121
122
int log2ValuesPerWidth = LOG2_ARRAY_LONG_INDEX_SCALE - log2ArrayIndexScale;
123
int wi = 0;
124
for (; wi < length >> log2ValuesPerWidth; wi++) {
125
long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
126
long av = U.getLongUnaligned(a, aOffset + bi);
127
long bv = U.getLongUnaligned(b, bOffset + bi);
128
if (av != bv) {
129
long x = av ^ bv;
130
int o = BIG_ENDIAN
131
? Long.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
132
: Long.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
133
return (wi << log2ValuesPerWidth) + o;
134
}
135
}
136
137
// Calculate the tail of remaining elements to check
138
int tail = length - (wi << log2ValuesPerWidth);
139
140
if (log2ArrayIndexScale < LOG2_ARRAY_INT_INDEX_SCALE) {
141
int wordTail = 1 << (LOG2_ARRAY_INT_INDEX_SCALE - log2ArrayIndexScale);
142
// Handle 4 bytes or 2 chars in the tail using int width
143
if (tail >= wordTail) {
144
long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;
145
int av = U.getIntUnaligned(a, aOffset + bi);
146
int bv = U.getIntUnaligned(b, bOffset + bi);
147
if (av != bv) {
148
int x = av ^ bv;
149
int o = BIG_ENDIAN
150
? Integer.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)
151
: Integer.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);
152
return (wi << log2ValuesPerWidth) + o;
153
}
154
tail -= wordTail;
155
}
156
return ~tail;
157
}
158
else {
159
return ~tail;
160
}
161
}
162
163
// Booleans
164
// Each boolean element takes up one byte
165
166
public static int mismatch(boolean[] a,
167
boolean[] b,
168
int length) {
169
int i = 0;
170
if (length > 7) {
171
if (a[0] != b[0])
172
return 0;
173
i = vectorizedMismatch(
174
a, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
175
b, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,
176
length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
177
if (i >= 0)
178
return i;
179
i = length - ~i;
180
}
181
for (; i < length; i++) {
182
if (a[i] != b[i])
183
return i;
184
}
185
return -1;
186
}
187
188
public static int mismatch(boolean[] a, int aFromIndex,
189
boolean[] b, int bFromIndex,
190
int length) {
191
int i = 0;
192
if (length > 7) {
193
if (a[aFromIndex] != b[bFromIndex])
194
return 0;
195
int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex;
196
int bOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + bFromIndex;
197
i = vectorizedMismatch(
198
a, aOffset,
199
b, bOffset,
200
length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);
201
if (i >= 0)
202
return i;
203
i = length - ~i;
204
}
205
for (; i < length; i++) {
206
if (a[aFromIndex + i] != b[bFromIndex + i])
207
return i;
208
}
209
return -1;
210
}
211
212
213
// Bytes
214
215
/**
216
* Find the index of a mismatch between two arrays.
217
*
218
* <p>This method does not perform bounds checks. It is the responsibility
219
* of the caller to perform such bounds checks before calling this method.
220
*
221
* @param a the first array to be tested for a mismatch
222
* @param b the second array to be tested for a mismatch
223
* @param length the number of bytes from each array to check
224
* @return the index of a mismatch between the two arrays, otherwise -1 if
225
* no mismatch. The index will be within the range of (inclusive) 0 to
226
* (exclusive) the smaller of the two array lengths.
227
*/
228
public static int mismatch(byte[] a,
229
byte[] b,
230
int length) {
231
// ISSUE: defer to index receiving methods if performance is good
232
// assert length <= a.length
233
// assert length <= b.length
234
235
int i = 0;
236
if (length > 7) {
237
if (a[0] != b[0])
238
return 0;
239
i = vectorizedMismatch(
240
a, Unsafe.ARRAY_BYTE_BASE_OFFSET,
241
b, Unsafe.ARRAY_BYTE_BASE_OFFSET,
242
length, LOG2_ARRAY_BYTE_INDEX_SCALE);
243
if (i >= 0)
244
return i;
245
// Align to tail
246
i = length - ~i;
247
// assert i >= 0 && i <= 7;
248
}
249
// Tail < 8 bytes
250
for (; i < length; i++) {
251
if (a[i] != b[i])
252
return i;
253
}
254
return -1;
255
}
256
257
/**
258
* Find the relative index of a mismatch between two arrays starting from
259
* given indexes.
260
*
261
* <p>This method does not perform bounds checks. It is the responsibility
262
* of the caller to perform such bounds checks before calling this method.
263
*
264
* @param a the first array to be tested for a mismatch
265
* @param aFromIndex the index of the first element (inclusive) in the first
266
* array to be compared
267
* @param b the second array to be tested for a mismatch
268
* @param bFromIndex the index of the first element (inclusive) in the
269
* second array to be compared
270
* @param length the number of bytes from each array to check
271
* @return the relative index of a mismatch between the two arrays,
272
* otherwise -1 if no mismatch. The index will be within the range of
273
* (inclusive) 0 to (exclusive) the smaller of the two array bounds.
274
*/
275
public static int mismatch(byte[] a, int aFromIndex,
276
byte[] b, int bFromIndex,
277
int length) {
278
// assert 0 <= aFromIndex < a.length
279
// assert 0 <= aFromIndex + length <= a.length
280
// assert 0 <= bFromIndex < b.length
281
// assert 0 <= bFromIndex + length <= b.length
282
// assert length >= 0
283
284
int i = 0;
285
if (length > 7) {
286
if (a[aFromIndex] != b[bFromIndex])
287
return 0;
288
int aOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + aFromIndex;
289
int bOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + bFromIndex;
290
i = vectorizedMismatch(
291
a, aOffset,
292
b, bOffset,
293
length, LOG2_ARRAY_BYTE_INDEX_SCALE);
294
if (i >= 0)
295
return i;
296
i = length - ~i;
297
}
298
for (; i < length; i++) {
299
if (a[aFromIndex + i] != b[bFromIndex + i])
300
return i;
301
}
302
return -1;
303
}
304
305
306
// Chars
307
308
public static int mismatch(char[] a,
309
char[] b,
310
int length) {
311
int i = 0;
312
if (length > 3) {
313
if (a[0] != b[0])
314
return 0;
315
i = vectorizedMismatch(
316
a, Unsafe.ARRAY_CHAR_BASE_OFFSET,
317
b, Unsafe.ARRAY_CHAR_BASE_OFFSET,
318
length, LOG2_ARRAY_CHAR_INDEX_SCALE);
319
if (i >= 0)
320
return i;
321
i = length - ~i;
322
}
323
for (; i < length; i++) {
324
if (a[i] != b[i])
325
return i;
326
}
327
return -1;
328
}
329
330
public static int mismatch(char[] a, int aFromIndex,
331
char[] b, int bFromIndex,
332
int length) {
333
int i = 0;
334
if (length > 3) {
335
if (a[aFromIndex] != b[bFromIndex])
336
return 0;
337
int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
338
int bOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);
339
i = vectorizedMismatch(
340
a, aOffset,
341
b, bOffset,
342
length, LOG2_ARRAY_CHAR_INDEX_SCALE);
343
if (i >= 0)
344
return i;
345
i = length - ~i;
346
}
347
for (; i < length; i++) {
348
if (a[aFromIndex + i] != b[bFromIndex + i])
349
return i;
350
}
351
return -1;
352
}
353
354
355
// Shorts
356
357
public static int mismatch(short[] a,
358
short[] b,
359
int length) {
360
int i = 0;
361
if (length > 3) {
362
if (a[0] != b[0])
363
return 0;
364
i = vectorizedMismatch(
365
a, Unsafe.ARRAY_SHORT_BASE_OFFSET,
366
b, Unsafe.ARRAY_SHORT_BASE_OFFSET,
367
length, LOG2_ARRAY_SHORT_INDEX_SCALE);
368
if (i >= 0)
369
return i;
370
i = length - ~i;
371
}
372
for (; i < length; i++) {
373
if (a[i] != b[i])
374
return i;
375
}
376
return -1;
377
}
378
379
public static int mismatch(short[] a, int aFromIndex,
380
short[] b, int bFromIndex,
381
int length) {
382
int i = 0;
383
if (length > 3) {
384
if (a[aFromIndex] != b[bFromIndex])
385
return 0;
386
int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
387
int bOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);
388
i = vectorizedMismatch(
389
a, aOffset,
390
b, bOffset,
391
length, LOG2_ARRAY_SHORT_INDEX_SCALE);
392
if (i >= 0)
393
return i;
394
i = length - ~i;
395
}
396
for (; i < length; i++) {
397
if (a[aFromIndex + i] != b[bFromIndex + i])
398
return i;
399
}
400
return -1;
401
}
402
403
404
// Ints
405
406
public static int mismatch(int[] a,
407
int[] b,
408
int length) {
409
int i = 0;
410
if (length > 1) {
411
if (a[0] != b[0])
412
return 0;
413
i = vectorizedMismatch(
414
a, Unsafe.ARRAY_INT_BASE_OFFSET,
415
b, Unsafe.ARRAY_INT_BASE_OFFSET,
416
length, LOG2_ARRAY_INT_INDEX_SCALE);
417
if (i >= 0)
418
return i;
419
i = length - ~i;
420
}
421
for (; i < length; i++) {
422
if (a[i] != b[i])
423
return i;
424
}
425
return -1;
426
}
427
428
public static int mismatch(int[] a, int aFromIndex,
429
int[] b, int bFromIndex,
430
int length) {
431
int i = 0;
432
if (length > 1) {
433
if (a[aFromIndex] != b[bFromIndex])
434
return 0;
435
int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
436
int bOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);
437
i = vectorizedMismatch(
438
a, aOffset,
439
b, bOffset,
440
length, LOG2_ARRAY_INT_INDEX_SCALE);
441
if (i >= 0)
442
return i;
443
i = length - ~i;
444
}
445
for (; i < length; i++) {
446
if (a[aFromIndex + i] != b[bFromIndex + i])
447
return i;
448
}
449
return -1;
450
}
451
452
453
// Floats
454
455
public static int mismatch(float[] a,
456
float[] b,
457
int length) {
458
return mismatch(a, 0, b, 0, length);
459
}
460
461
public static int mismatch(float[] a, int aFromIndex,
462
float[] b, int bFromIndex,
463
int length) {
464
int i = 0;
465
if (length > 1) {
466
if (Float.floatToRawIntBits(a[aFromIndex]) == Float.floatToRawIntBits(b[bFromIndex])) {
467
int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
468
int bOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);
469
i = vectorizedMismatch(
470
a, aOffset,
471
b, bOffset,
472
length, LOG2_ARRAY_FLOAT_INDEX_SCALE);
473
}
474
// Mismatched
475
if (i >= 0) {
476
// Check if mismatch is not associated with two NaN values
477
if (!Float.isNaN(a[aFromIndex + i]) || !Float.isNaN(b[bFromIndex + i]))
478
return i;
479
480
// Mismatch on two different NaN values that are normalized to match
481
// Fall back to slow mechanism
482
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
483
// However, requires that returned value be relative to input ranges
484
i++;
485
}
486
// Matched
487
else {
488
i = length - ~i;
489
}
490
}
491
for (; i < length; i++) {
492
if (Float.floatToIntBits(a[aFromIndex + i]) != Float.floatToIntBits(b[bFromIndex + i]))
493
return i;
494
}
495
return -1;
496
}
497
498
// 64 bit sizes
499
500
// Long
501
502
public static int mismatch(long[] a,
503
long[] b,
504
int length) {
505
if (length == 0) {
506
return -1;
507
}
508
if (a[0] != b[0])
509
return 0;
510
int i = vectorizedMismatch(
511
a, Unsafe.ARRAY_LONG_BASE_OFFSET,
512
b, Unsafe.ARRAY_LONG_BASE_OFFSET,
513
length, LOG2_ARRAY_LONG_INDEX_SCALE);
514
return i >= 0 ? i : -1;
515
}
516
517
public static int mismatch(long[] a, int aFromIndex,
518
long[] b, int bFromIndex,
519
int length) {
520
if (length == 0) {
521
return -1;
522
}
523
if (a[aFromIndex] != b[bFromIndex])
524
return 0;
525
int aOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
526
int bOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);
527
int i = vectorizedMismatch(
528
a, aOffset,
529
b, bOffset,
530
length, LOG2_ARRAY_LONG_INDEX_SCALE);
531
return i >= 0 ? i : -1;
532
}
533
534
535
// Double
536
537
public static int mismatch(double[] a,
538
double[] b,
539
int length) {
540
return mismatch(a, 0, b, 0, length);
541
}
542
543
public static int mismatch(double[] a, int aFromIndex,
544
double[] b, int bFromIndex,
545
int length) {
546
if (length == 0) {
547
return -1;
548
}
549
int i = 0;
550
if (Double.doubleToRawLongBits(a[aFromIndex]) == Double.doubleToRawLongBits(b[bFromIndex])) {
551
int aOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
552
int bOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);
553
i = vectorizedMismatch(
554
a, aOffset,
555
b, bOffset,
556
length, LOG2_ARRAY_DOUBLE_INDEX_SCALE);
557
}
558
if (i >= 0) {
559
// Check if mismatch is not associated with two NaN values
560
if (!Double.isNaN(a[aFromIndex + i]) || !Double.isNaN(b[bFromIndex + i]))
561
return i;
562
563
// Mismatch on two different NaN values that are normalized to match
564
// Fall back to slow mechanism
565
// ISSUE: Consider looping over vectorizedMismatch adjusting ranges
566
// However, requires that returned value be relative to input ranges
567
i++;
568
for (; i < length; i++) {
569
if (Double.doubleToLongBits(a[aFromIndex + i]) != Double.doubleToLongBits(b[bFromIndex + i]))
570
return i;
571
}
572
}
573
574
return -1;
575
}
576
577
/**
578
* A soft maximum array length imposed by array growth computations.
579
* Some JVMs (such as HotSpot) have an implementation limit that will cause
580
*
581
* OutOfMemoryError("Requested array size exceeds VM limit")
582
*
583
* to be thrown if a request is made to allocate an array of some length near
584
* Integer.MAX_VALUE, even if there is sufficient heap available. The actual
585
* limit might depend on some JVM implementation-specific characteristics such
586
* as the object header size. The soft maximum value is chosen conservatively so
587
* as to be smaller than any implementation limit that is likely to be encountered.
588
*/
589
public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;
590
591
/**
592
* Computes a new array length given an array's current length, a minimum growth
593
* amount, and a preferred growth amount. The computation is done in an overflow-safe
594
* fashion.
595
*
596
* This method is used by objects that contain an array that might need to be grown
597
* in order to fulfill some immediate need (the minimum growth amount) but would also
598
* like to request more space (the preferred growth amount) in order to accommodate
599
* potential future needs. The returned length is usually clamped at the soft maximum
600
* length in order to avoid hitting the JVM implementation limit. However, the soft
601
* maximum will be exceeded if the minimum growth amount requires it.
602
*
603
* If the preferred growth amount is less than the minimum growth amount, the
604
* minimum growth amount is used as the preferred growth amount.
605
*
606
* The preferred length is determined by adding the preferred growth amount to the
607
* current length. If the preferred length does not exceed the soft maximum length
608
* (SOFT_MAX_ARRAY_LENGTH) then the preferred length is returned.
609
*
610
* If the preferred length exceeds the soft maximum, we use the minimum growth
611
* amount. The minimum required length is determined by adding the minimum growth
612
* amount to the current length. If the minimum required length exceeds Integer.MAX_VALUE,
613
* then this method throws OutOfMemoryError. Otherwise, this method returns the greater of
614
* the soft maximum or the minimum required length.
615
*
616
* Note that this method does not do any array allocation itself; it only does array
617
* length growth computations. However, it will throw OutOfMemoryError as noted above.
618
*
619
* Note also that this method cannot detect the JVM's implementation limit, and it
620
* may compute and return a length value up to and including Integer.MAX_VALUE that
621
* might exceed the JVM's implementation limit. In that case, the caller will likely
622
* attempt an array allocation with that length and encounter an OutOfMemoryError.
623
* Of course, regardless of the length value returned from this method, the caller
624
* may encounter OutOfMemoryError if there is insufficient heap to fulfill the request.
625
*
626
* @param oldLength current length of the array (must be nonnegative)
627
* @param minGrowth minimum required growth amount (must be positive)
628
* @param prefGrowth preferred growth amount
629
* @return the new array length
630
* @throws OutOfMemoryError if the new length would exceed Integer.MAX_VALUE
631
*/
632
public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
633
// preconditions not checked because of inlining
634
// assert oldLength >= 0
635
// assert minGrowth > 0
636
637
int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow
638
if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {
639
return prefLength;
640
} else {
641
// put code cold in a separate method
642
return hugeLength(oldLength, minGrowth);
643
}
644
}
645
646
private static int hugeLength(int oldLength, int minGrowth) {
647
int minLength = oldLength + minGrowth;
648
if (minLength < 0) { // overflow
649
throw new OutOfMemoryError(
650
"Required array length " + oldLength + " + " + minGrowth + " is too large");
651
} else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {
652
return SOFT_MAX_ARRAY_LENGTH;
653
} else {
654
return minLength;
655
}
656
}
657
}
658
659