1 /* 2 * Copyright (c) 2015, 2019, 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.HotSpotIntrinsicCandidate; 28 import jdk.internal.misc.Unsafe; 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 @HotSpotIntrinsicCandidate 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 /** 164 * Mismatch over long lengths. 165 */ 166 public static long vectorizedMismatchLargeForBytes(Object a, long aOffset, 167 Object b, long bOffset, 168 long length) { 169 long off = 0; 170 long remaining = length; 171 int i, size; 172 boolean lastSubRange = false; 173 while (remaining > 7 && !lastSubRange) { 174 if (remaining > Integer.MAX_VALUE) { 175 size = Integer.MAX_VALUE; 176 } else { 177 size = (int) remaining; 178 lastSubRange = true; 179 } 180 i = vectorizedMismatch( 181 a, aOffset + off, 182 b, bOffset + off, 183 size, LOG2_ARRAY_BYTE_INDEX_SCALE); 184 if (i >= 0) 185 return off + i; 186 187 i = size - ~i; 188 off += i; 189 remaining -= i; 190 } 191 return ~remaining; 192 } 193 194 // Booleans 195 // Each boolean element takes up one byte 196 197 public static int mismatch(boolean[] a, 198 boolean[] b, 199 int length) { 200 int i = 0; 201 if (length > 7) { 202 if (a[0] != b[0]) 203 return 0; 204 i = vectorizedMismatch( 205 a, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 206 b, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 207 length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE); 208 if (i >= 0) 209 return i; 210 i = length - ~i; 211 } 212 for (; i < length; i++) { 213 if (a[i] != b[i]) 214 return i; 215 } 216 return -1; 217 } 218 219 public static int mismatch(boolean[] a, int aFromIndex, 220 boolean[] b, int bFromIndex, 221 int length) { 222 int i = 0; 223 if (length > 7) { 224 if (a[aFromIndex] != b[bFromIndex]) 225 return 0; 226 int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex; 227 int bOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + bFromIndex; 228 i = vectorizedMismatch( 229 a, aOffset, 230 b, bOffset, 231 length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE); 232 if (i >= 0) 233 return i; 234 i = length - ~i; 235 } 236 for (; i < length; i++) { 237 if (a[aFromIndex + i] != b[bFromIndex + i]) 238 return i; 239 } 240 return -1; 241 } 242 243 244 // Bytes 245 246 /** 247 * Find the index of a mismatch between two arrays. 248 * 249 * <p>This method does not perform bounds checks. It is the responsibility 250 * of the caller to perform such bounds checks before calling this method. 251 * 252 * @param a the first array to be tested for a mismatch 253 * @param b the second array to be tested for a mismatch 254 * @param length the number of bytes from each array to check 255 * @return the index of a mismatch between the two arrays, otherwise -1 if 256 * no mismatch. The index will be within the range of (inclusive) 0 to 257 * (exclusive) the smaller of the two array lengths. 258 */ 259 public static int mismatch(byte[] a, 260 byte[] b, 261 int length) { 262 // ISSUE: defer to index receiving methods if performance is good 263 // assert length <= a.length 264 // assert length <= b.length 265 266 int i = 0; 267 if (length > 7) { 268 if (a[0] != b[0]) 269 return 0; 270 i = vectorizedMismatch( 271 a, Unsafe.ARRAY_BYTE_BASE_OFFSET, 272 b, Unsafe.ARRAY_BYTE_BASE_OFFSET, 273 length, LOG2_ARRAY_BYTE_INDEX_SCALE); 274 if (i >= 0) 275 return i; 276 // Align to tail 277 i = length - ~i; 278 // assert i >= 0 && i <= 7; 279 } 280 // Tail < 8 bytes 281 for (; i < length; i++) { 282 if (a[i] != b[i]) 283 return i; 284 } 285 return -1; 286 } 287 288 /** 289 * Find the relative index of a mismatch between two arrays starting from 290 * given indexes. 291 * 292 * <p>This method does not perform bounds checks. It is the responsibility 293 * of the caller to perform such bounds checks before calling this method. 294 * 295 * @param a the first array to be tested for a mismatch 296 * @param aFromIndex the index of the first element (inclusive) in the first 297 * array to be compared 298 * @param b the second array to be tested for a mismatch 299 * @param bFromIndex the index of the first element (inclusive) in the 300 * second array to be compared 301 * @param length the number of bytes from each array to check 302 * @return the relative index of a mismatch between the two arrays, 303 * otherwise -1 if no mismatch. The index will be within the range of 304 * (inclusive) 0 to (exclusive) the smaller of the two array bounds. 305 */ 306 public static int mismatch(byte[] a, int aFromIndex, 307 byte[] b, int bFromIndex, 308 int length) { 309 // assert 0 <= aFromIndex < a.length 310 // assert 0 <= aFromIndex + length <= a.length 311 // assert 0 <= bFromIndex < b.length 312 // assert 0 <= bFromIndex + length <= b.length 313 // assert length >= 0 314 315 int i = 0; 316 if (length > 7) { 317 if (a[aFromIndex] != b[bFromIndex]) 318 return 0; 319 int aOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + aFromIndex; 320 int bOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + bFromIndex; 321 i = vectorizedMismatch( 322 a, aOffset, 323 b, bOffset, 324 length, LOG2_ARRAY_BYTE_INDEX_SCALE); 325 if (i >= 0) 326 return i; 327 i = length - ~i; 328 } 329 for (; i < length; i++) { 330 if (a[aFromIndex + i] != b[bFromIndex + i]) 331 return i; 332 } 333 return -1; 334 } 335 336 337 // Chars 338 339 public static int mismatch(char[] a, 340 char[] b, 341 int length) { 342 int i = 0; 343 if (length > 3) { 344 if (a[0] != b[0]) 345 return 0; 346 i = vectorizedMismatch( 347 a, Unsafe.ARRAY_CHAR_BASE_OFFSET, 348 b, Unsafe.ARRAY_CHAR_BASE_OFFSET, 349 length, LOG2_ARRAY_CHAR_INDEX_SCALE); 350 if (i >= 0) 351 return i; 352 i = length - ~i; 353 } 354 for (; i < length; i++) { 355 if (a[i] != b[i]) 356 return i; 357 } 358 return -1; 359 } 360 361 public static int mismatch(char[] a, int aFromIndex, 362 char[] b, int bFromIndex, 363 int length) { 364 int i = 0; 365 if (length > 3) { 366 if (a[aFromIndex] != b[bFromIndex]) 367 return 0; 368 int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE); 369 int bOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE); 370 i = vectorizedMismatch( 371 a, aOffset, 372 b, bOffset, 373 length, LOG2_ARRAY_CHAR_INDEX_SCALE); 374 if (i >= 0) 375 return i; 376 i = length - ~i; 377 } 378 for (; i < length; i++) { 379 if (a[aFromIndex + i] != b[bFromIndex + i]) 380 return i; 381 } 382 return -1; 383 } 384 385 386 // Shorts 387 388 public static int mismatch(short[] a, 389 short[] b, 390 int length) { 391 int i = 0; 392 if (length > 3) { 393 if (a[0] != b[0]) 394 return 0; 395 i = vectorizedMismatch( 396 a, Unsafe.ARRAY_SHORT_BASE_OFFSET, 397 b, Unsafe.ARRAY_SHORT_BASE_OFFSET, 398 length, LOG2_ARRAY_SHORT_INDEX_SCALE); 399 if (i >= 0) 400 return i; 401 i = length - ~i; 402 } 403 for (; i < length; i++) { 404 if (a[i] != b[i]) 405 return i; 406 } 407 return -1; 408 } 409 410 public static int mismatch(short[] a, int aFromIndex, 411 short[] b, int bFromIndex, 412 int length) { 413 int i = 0; 414 if (length > 3) { 415 if (a[aFromIndex] != b[bFromIndex]) 416 return 0; 417 int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE); 418 int bOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE); 419 i = vectorizedMismatch( 420 a, aOffset, 421 b, bOffset, 422 length, LOG2_ARRAY_SHORT_INDEX_SCALE); 423 if (i >= 0) 424 return i; 425 i = length - ~i; 426 } 427 for (; i < length; i++) { 428 if (a[aFromIndex + i] != b[bFromIndex + i]) 429 return i; 430 } 431 return -1; 432 } 433 434 435 // Ints 436 437 public static int mismatch(int[] a, 438 int[] b, 439 int length) { 440 int i = 0; 441 if (length > 1) { 442 if (a[0] != b[0]) 443 return 0; 444 i = vectorizedMismatch( 445 a, Unsafe.ARRAY_INT_BASE_OFFSET, 446 b, Unsafe.ARRAY_INT_BASE_OFFSET, 447 length, LOG2_ARRAY_INT_INDEX_SCALE); 448 if (i >= 0) 449 return i; 450 i = length - ~i; 451 } 452 for (; i < length; i++) { 453 if (a[i] != b[i]) 454 return i; 455 } 456 return -1; 457 } 458 459 public static int mismatch(int[] a, int aFromIndex, 460 int[] b, int bFromIndex, 461 int length) { 462 int i = 0; 463 if (length > 1) { 464 if (a[aFromIndex] != b[bFromIndex]) 465 return 0; 466 int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE); 467 int bOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_INT_INDEX_SCALE); 468 i = vectorizedMismatch( 469 a, aOffset, 470 b, bOffset, 471 length, LOG2_ARRAY_INT_INDEX_SCALE); 472 if (i >= 0) 473 return i; 474 i = length - ~i; 475 } 476 for (; i < length; i++) { 477 if (a[aFromIndex + i] != b[bFromIndex + i]) 478 return i; 479 } 480 return -1; 481 } 482 483 484 // Floats 485 486 public static int mismatch(float[] a, 487 float[] b, 488 int length) { 489 return mismatch(a, 0, b, 0, length); 490 } 491 492 public static int mismatch(float[] a, int aFromIndex, 493 float[] b, int bFromIndex, 494 int length) { 495 int i = 0; 496 if (length > 1) { 497 if (Float.floatToRawIntBits(a[aFromIndex]) == Float.floatToRawIntBits(b[bFromIndex])) { 498 int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE); 499 int bOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE); 500 i = vectorizedMismatch( 501 a, aOffset, 502 b, bOffset, 503 length, LOG2_ARRAY_FLOAT_INDEX_SCALE); 504 } 505 // Mismatched 506 if (i >= 0) { 507 // Check if mismatch is not associated with two NaN values 508 if (!Float.isNaN(a[aFromIndex + i]) || !Float.isNaN(b[bFromIndex + i])) 509 return i; 510 511 // Mismatch on two different NaN values that are normalized to match 512 // Fall back to slow mechanism 513 // ISSUE: Consider looping over vectorizedMismatch adjusting ranges 514 // However, requires that returned value be relative to input ranges 515 i++; 516 } 517 // Matched 518 else { 519 i = length - ~i; 520 } 521 } 522 for (; i < length; i++) { 523 if (Float.floatToIntBits(a[aFromIndex + i]) != Float.floatToIntBits(b[bFromIndex + i])) 524 return i; 525 } 526 return -1; 527 } 528 529 // 64 bit sizes 530 531 // Long 532 533 public static int mismatch(long[] a, 534 long[] b, 535 int length) { 536 if (length == 0) { 537 return -1; 538 } 539 if (a[0] != b[0]) 540 return 0; 541 int i = vectorizedMismatch( 542 a, Unsafe.ARRAY_LONG_BASE_OFFSET, 543 b, Unsafe.ARRAY_LONG_BASE_OFFSET, 544 length, LOG2_ARRAY_LONG_INDEX_SCALE); 545 return i >= 0 ? i : -1; 546 } 547 548 public static int mismatch(long[] a, int aFromIndex, 549 long[] b, int bFromIndex, 550 int length) { 551 if (length == 0) { 552 return -1; 553 } 554 if (a[aFromIndex] != b[bFromIndex]) 555 return 0; 556 int aOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE); 557 int bOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE); 558 int i = vectorizedMismatch( 559 a, aOffset, 560 b, bOffset, 561 length, LOG2_ARRAY_LONG_INDEX_SCALE); 562 return i >= 0 ? i : -1; 563 } 564 565 566 // Double 567 568 public static int mismatch(double[] a, 569 double[] b, 570 int length) { 571 return mismatch(a, 0, b, 0, length); 572 } 573 574 public static int mismatch(double[] a, int aFromIndex, 575 double[] b, int bFromIndex, 576 int length) { 577 if (length == 0) { 578 return -1; 579 } 580 int i = 0; 581 if (Double.doubleToRawLongBits(a[aFromIndex]) == Double.doubleToRawLongBits(b[bFromIndex])) { 582 int aOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE); 583 int bOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE); 584 i = vectorizedMismatch( 585 a, aOffset, 586 b, bOffset, 587 length, LOG2_ARRAY_DOUBLE_INDEX_SCALE); 588 } 589 if (i >= 0) { 590 // Check if mismatch is not associated with two NaN values 591 if (!Double.isNaN(a[aFromIndex + i]) || !Double.isNaN(b[bFromIndex + i])) 592 return i; 593 594 // Mismatch on two different NaN values that are normalized to match 595 // Fall back to slow mechanism 596 // ISSUE: Consider looping over vectorizedMismatch adjusting ranges 597 // However, requires that returned value be relative to input ranges 598 i++; 599 for (; i < length; i++) { 600 if (Double.doubleToLongBits(a[aFromIndex + i]) != Double.doubleToLongBits(b[bFromIndex + i])) 601 return i; 602 } 603 } 604 605 return -1; 606 } 607 608 /** 609 * The maximum length of array to allocate (unless necessary). 610 * Some VMs reserve some header words in an array. 611 * Attempts to allocate larger arrays may result in 612 * {@code OutOfMemoryError: Requested array size exceeds VM limit} 613 */ 614 public static final int MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8; 615 616 /** 617 * Calculates a new array length given an array's current length, a preferred 618 * growth value, and a minimum growth value. If the preferred growth value 619 * is less than the minimum growth value, the minimum growth value is used in 620 * its place. If the sum of the current length and the preferred growth 621 * value does not exceed {@link #MAX_ARRAY_LENGTH}, that sum is returned. 622 * If the sum of the current length and the minimum growth value does not 623 * exceed {@code MAX_ARRAY_LENGTH}, then {@code MAX_ARRAY_LENGTH} is returned. 624 * If the sum does not overflow an int, then {@code Integer.MAX_VALUE} is 625 * returned. Otherwise, {@code OutOfMemoryError} is thrown. 626 * 627 * @param oldLength current length of the array (must be non negative) 628 * @param minGrowth minimum required growth of the array length (must be 629 * positive) 630 * @param prefGrowth preferred growth of the array length (ignored, if less 631 * then {@code minGrowth}) 632 * @return the new length of the array 633 * @throws OutOfMemoryError if increasing {@code oldLength} by 634 * {@code minGrowth} overflows. 635 */ 636 public static int newLength(int oldLength, int minGrowth, int prefGrowth) { 637 // assert oldLength >= 0 638 // assert minGrowth > 0 639 640 int newLength = Math.max(minGrowth, prefGrowth) + oldLength; 641 if (newLength - MAX_ARRAY_LENGTH <= 0) { 642 return newLength; 643 } 644 return hugeLength(oldLength, minGrowth); 645 } 646 647 private static int hugeLength(int oldLength, int minGrowth) { 648 int minLength = oldLength + minGrowth; 649 if (minLength < 0) { // overflow 650 throw new OutOfMemoryError("Required array length too large"); 651 } 652 if (minLength <= MAX_ARRAY_LENGTH) { 653 return MAX_ARRAY_LENGTH; 654 } 655 return Integer.MAX_VALUE; 656 } 657 }