Path: blob/master/src/java.base/share/classes/jdk/internal/util/ArraysSupport.java
41159 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/24package jdk.internal.util;2526import jdk.internal.misc.Unsafe;27import jdk.internal.vm.annotation.IntrinsicCandidate;2829/**30* Utility methods to work with arrays. This includes a set of methods31* to find a mismatch between two primitive arrays. Also included is32* a method to calculate the new length of an array to be reallocated.33*34* <p>Array equality and lexicographical comparison can be built on top of35* array mismatch functionality.36*37* <p>The mismatch method implementation, {@link #vectorizedMismatch}, leverages38* vector-based techniques to access and compare the contents of two arrays.39* The Java implementation uses {@code Unsafe.getLongUnaligned} to access the40* content of an array, thus access is supported on platforms that do not41* support unaligned access. For a byte[] array, 8 bytes (64 bits) can be42* accessed and compared as a unit rather than individually, which increases43* the performance when the method is compiled by the HotSpot VM. On supported44* platforms the mismatch implementation is intrinsified to leverage SIMD45* instructions. So for a byte[] array, 16 bytes (128 bits), 32 bytes46* (256 bits), and perhaps in the future even 64 bytes (512 bits), platform47* permitting, can be accessed and compared as a unit, which further increases48* the performance over the Java implementation.49*50* <p>None of the mismatch methods perform array bounds checks. It is the51* responsibility of the caller (direct or otherwise) to perform such checks52* before calling this method.53*/54public class ArraysSupport {55static final Unsafe U = Unsafe.getUnsafe();5657private static final boolean BIG_ENDIAN = U.isBigEndian();5859public static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE);60public static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE);61public static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE);62public static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE);63public static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE);64public static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE);65public static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE);66public static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE);6768private static final int LOG2_BYTE_BIT_SIZE = exactLog2(Byte.SIZE);6970private static int exactLog2(int scale) {71if ((scale & (scale - 1)) != 0)72throw new Error("data type scale not a power of two");73return Integer.numberOfTrailingZeros(scale);74}7576private ArraysSupport() {}7778/**79* Find the relative index of the first mismatching pair of elements in two80* primitive arrays of the same component type. Pairs of elements will be81* tested in order relative to given offsets into both arrays.82*83* <p>This method does not perform type checks or bounds checks. It is the84* responsibility of the caller to perform such checks before calling this85* method.86*87* <p>The given offsets, in bytes, need not be aligned according to the88* given log<sub>2</sub> size the array elements. More specifically, an89* offset modulus the size need not be zero.90*91* @param a the first array to be tested for mismatch, or {@code null} for92* direct memory access93* @param aOffset the relative offset, in bytes, from the base address of94* the first array to test from, otherwise if the first array is95* {@code null}, an absolute address pointing to the first element to test.96* @param b the second array to be tested for mismatch, or {@code null} for97* direct memory access98* @param bOffset the relative offset, in bytes, from the base address of99* the second array to test from, otherwise if the second array is100* {@code null}, an absolute address pointing to the first element to test.101* @param length the number of array elements to test102* @param log2ArrayIndexScale log<sub>2</sub> of the array index scale, that103* corresponds to the size, in bytes, of an array element.104* @return if a mismatch is found a relative index, between 0 (inclusive)105* and {@code length} (exclusive), of the first mismatching pair of elements106* in the two arrays. Otherwise, if a mismatch is not found the bitwise107* compliment of the number of remaining pairs of elements to be checked in108* the tail of the two arrays.109*/110@IntrinsicCandidate111public static int vectorizedMismatch(Object a, long aOffset,112Object b, long bOffset,113int length,114int log2ArrayIndexScale) {115// assert a.getClass().isArray();116// assert b.getClass().isArray();117// assert 0 <= length <= sizeOf(a)118// assert 0 <= length <= sizeOf(b)119// assert 0 <= log2ArrayIndexScale <= 3120121int log2ValuesPerWidth = LOG2_ARRAY_LONG_INDEX_SCALE - log2ArrayIndexScale;122int wi = 0;123for (; wi < length >> log2ValuesPerWidth; wi++) {124long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;125long av = U.getLongUnaligned(a, aOffset + bi);126long bv = U.getLongUnaligned(b, bOffset + bi);127if (av != bv) {128long x = av ^ bv;129int o = BIG_ENDIAN130? Long.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)131: Long.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);132return (wi << log2ValuesPerWidth) + o;133}134}135136// Calculate the tail of remaining elements to check137int tail = length - (wi << log2ValuesPerWidth);138139if (log2ArrayIndexScale < LOG2_ARRAY_INT_INDEX_SCALE) {140int wordTail = 1 << (LOG2_ARRAY_INT_INDEX_SCALE - log2ArrayIndexScale);141// Handle 4 bytes or 2 chars in the tail using int width142if (tail >= wordTail) {143long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE;144int av = U.getIntUnaligned(a, aOffset + bi);145int bv = U.getIntUnaligned(b, bOffset + bi);146if (av != bv) {147int x = av ^ bv;148int o = BIG_ENDIAN149? Integer.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale)150: Integer.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale);151return (wi << log2ValuesPerWidth) + o;152}153tail -= wordTail;154}155return ~tail;156}157else {158return ~tail;159}160}161162// Booleans163// Each boolean element takes up one byte164165public static int mismatch(boolean[] a,166boolean[] b,167int length) {168int i = 0;169if (length > 7) {170if (a[0] != b[0])171return 0;172i = vectorizedMismatch(173a, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,174b, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET,175length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);176if (i >= 0)177return i;178i = length - ~i;179}180for (; i < length; i++) {181if (a[i] != b[i])182return i;183}184return -1;185}186187public static int mismatch(boolean[] a, int aFromIndex,188boolean[] b, int bFromIndex,189int length) {190int i = 0;191if (length > 7) {192if (a[aFromIndex] != b[bFromIndex])193return 0;194int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex;195int bOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + bFromIndex;196i = vectorizedMismatch(197a, aOffset,198b, bOffset,199length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE);200if (i >= 0)201return i;202i = length - ~i;203}204for (; i < length; i++) {205if (a[aFromIndex + i] != b[bFromIndex + i])206return i;207}208return -1;209}210211212// Bytes213214/**215* Find the index of a mismatch between two arrays.216*217* <p>This method does not perform bounds checks. It is the responsibility218* of the caller to perform such bounds checks before calling this method.219*220* @param a the first array to be tested for a mismatch221* @param b the second array to be tested for a mismatch222* @param length the number of bytes from each array to check223* @return the index of a mismatch between the two arrays, otherwise -1 if224* no mismatch. The index will be within the range of (inclusive) 0 to225* (exclusive) the smaller of the two array lengths.226*/227public static int mismatch(byte[] a,228byte[] b,229int length) {230// ISSUE: defer to index receiving methods if performance is good231// assert length <= a.length232// assert length <= b.length233234int i = 0;235if (length > 7) {236if (a[0] != b[0])237return 0;238i = vectorizedMismatch(239a, Unsafe.ARRAY_BYTE_BASE_OFFSET,240b, Unsafe.ARRAY_BYTE_BASE_OFFSET,241length, LOG2_ARRAY_BYTE_INDEX_SCALE);242if (i >= 0)243return i;244// Align to tail245i = length - ~i;246// assert i >= 0 && i <= 7;247}248// Tail < 8 bytes249for (; i < length; i++) {250if (a[i] != b[i])251return i;252}253return -1;254}255256/**257* Find the relative index of a mismatch between two arrays starting from258* given indexes.259*260* <p>This method does not perform bounds checks. It is the responsibility261* of the caller to perform such bounds checks before calling this method.262*263* @param a the first array to be tested for a mismatch264* @param aFromIndex the index of the first element (inclusive) in the first265* array to be compared266* @param b the second array to be tested for a mismatch267* @param bFromIndex the index of the first element (inclusive) in the268* second array to be compared269* @param length the number of bytes from each array to check270* @return the relative index of a mismatch between the two arrays,271* otherwise -1 if no mismatch. The index will be within the range of272* (inclusive) 0 to (exclusive) the smaller of the two array bounds.273*/274public static int mismatch(byte[] a, int aFromIndex,275byte[] b, int bFromIndex,276int length) {277// assert 0 <= aFromIndex < a.length278// assert 0 <= aFromIndex + length <= a.length279// assert 0 <= bFromIndex < b.length280// assert 0 <= bFromIndex + length <= b.length281// assert length >= 0282283int i = 0;284if (length > 7) {285if (a[aFromIndex] != b[bFromIndex])286return 0;287int aOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + aFromIndex;288int bOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + bFromIndex;289i = vectorizedMismatch(290a, aOffset,291b, bOffset,292length, LOG2_ARRAY_BYTE_INDEX_SCALE);293if (i >= 0)294return i;295i = length - ~i;296}297for (; i < length; i++) {298if (a[aFromIndex + i] != b[bFromIndex + i])299return i;300}301return -1;302}303304305// Chars306307public static int mismatch(char[] a,308char[] b,309int length) {310int i = 0;311if (length > 3) {312if (a[0] != b[0])313return 0;314i = vectorizedMismatch(315a, Unsafe.ARRAY_CHAR_BASE_OFFSET,316b, Unsafe.ARRAY_CHAR_BASE_OFFSET,317length, LOG2_ARRAY_CHAR_INDEX_SCALE);318if (i >= 0)319return i;320i = length - ~i;321}322for (; i < length; i++) {323if (a[i] != b[i])324return i;325}326return -1;327}328329public static int mismatch(char[] a, int aFromIndex,330char[] b, int bFromIndex,331int length) {332int i = 0;333if (length > 3) {334if (a[aFromIndex] != b[bFromIndex])335return 0;336int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);337int bOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE);338i = vectorizedMismatch(339a, aOffset,340b, bOffset,341length, LOG2_ARRAY_CHAR_INDEX_SCALE);342if (i >= 0)343return i;344i = length - ~i;345}346for (; i < length; i++) {347if (a[aFromIndex + i] != b[bFromIndex + i])348return i;349}350return -1;351}352353354// Shorts355356public static int mismatch(short[] a,357short[] b,358int length) {359int i = 0;360if (length > 3) {361if (a[0] != b[0])362return 0;363i = vectorizedMismatch(364a, Unsafe.ARRAY_SHORT_BASE_OFFSET,365b, Unsafe.ARRAY_SHORT_BASE_OFFSET,366length, LOG2_ARRAY_SHORT_INDEX_SCALE);367if (i >= 0)368return i;369i = length - ~i;370}371for (; i < length; i++) {372if (a[i] != b[i])373return i;374}375return -1;376}377378public static int mismatch(short[] a, int aFromIndex,379short[] b, int bFromIndex,380int length) {381int i = 0;382if (length > 3) {383if (a[aFromIndex] != b[bFromIndex])384return 0;385int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);386int bOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE);387i = vectorizedMismatch(388a, aOffset,389b, bOffset,390length, LOG2_ARRAY_SHORT_INDEX_SCALE);391if (i >= 0)392return i;393i = length - ~i;394}395for (; i < length; i++) {396if (a[aFromIndex + i] != b[bFromIndex + i])397return i;398}399return -1;400}401402403// Ints404405public static int mismatch(int[] a,406int[] b,407int length) {408int i = 0;409if (length > 1) {410if (a[0] != b[0])411return 0;412i = vectorizedMismatch(413a, Unsafe.ARRAY_INT_BASE_OFFSET,414b, Unsafe.ARRAY_INT_BASE_OFFSET,415length, LOG2_ARRAY_INT_INDEX_SCALE);416if (i >= 0)417return i;418i = length - ~i;419}420for (; i < length; i++) {421if (a[i] != b[i])422return i;423}424return -1;425}426427public static int mismatch(int[] a, int aFromIndex,428int[] b, int bFromIndex,429int length) {430int i = 0;431if (length > 1) {432if (a[aFromIndex] != b[bFromIndex])433return 0;434int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);435int bOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_INT_INDEX_SCALE);436i = vectorizedMismatch(437a, aOffset,438b, bOffset,439length, LOG2_ARRAY_INT_INDEX_SCALE);440if (i >= 0)441return i;442i = length - ~i;443}444for (; i < length; i++) {445if (a[aFromIndex + i] != b[bFromIndex + i])446return i;447}448return -1;449}450451452// Floats453454public static int mismatch(float[] a,455float[] b,456int length) {457return mismatch(a, 0, b, 0, length);458}459460public static int mismatch(float[] a, int aFromIndex,461float[] b, int bFromIndex,462int length) {463int i = 0;464if (length > 1) {465if (Float.floatToRawIntBits(a[aFromIndex]) == Float.floatToRawIntBits(b[bFromIndex])) {466int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);467int bOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE);468i = vectorizedMismatch(469a, aOffset,470b, bOffset,471length, LOG2_ARRAY_FLOAT_INDEX_SCALE);472}473// Mismatched474if (i >= 0) {475// Check if mismatch is not associated with two NaN values476if (!Float.isNaN(a[aFromIndex + i]) || !Float.isNaN(b[bFromIndex + i]))477return i;478479// Mismatch on two different NaN values that are normalized to match480// Fall back to slow mechanism481// ISSUE: Consider looping over vectorizedMismatch adjusting ranges482// However, requires that returned value be relative to input ranges483i++;484}485// Matched486else {487i = length - ~i;488}489}490for (; i < length; i++) {491if (Float.floatToIntBits(a[aFromIndex + i]) != Float.floatToIntBits(b[bFromIndex + i]))492return i;493}494return -1;495}496497// 64 bit sizes498499// Long500501public static int mismatch(long[] a,502long[] b,503int length) {504if (length == 0) {505return -1;506}507if (a[0] != b[0])508return 0;509int i = vectorizedMismatch(510a, Unsafe.ARRAY_LONG_BASE_OFFSET,511b, Unsafe.ARRAY_LONG_BASE_OFFSET,512length, LOG2_ARRAY_LONG_INDEX_SCALE);513return i >= 0 ? i : -1;514}515516public static int mismatch(long[] a, int aFromIndex,517long[] b, int bFromIndex,518int length) {519if (length == 0) {520return -1;521}522if (a[aFromIndex] != b[bFromIndex])523return 0;524int aOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);525int bOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE);526int i = vectorizedMismatch(527a, aOffset,528b, bOffset,529length, LOG2_ARRAY_LONG_INDEX_SCALE);530return i >= 0 ? i : -1;531}532533534// Double535536public static int mismatch(double[] a,537double[] b,538int length) {539return mismatch(a, 0, b, 0, length);540}541542public static int mismatch(double[] a, int aFromIndex,543double[] b, int bFromIndex,544int length) {545if (length == 0) {546return -1;547}548int i = 0;549if (Double.doubleToRawLongBits(a[aFromIndex]) == Double.doubleToRawLongBits(b[bFromIndex])) {550int aOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);551int bOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE);552i = vectorizedMismatch(553a, aOffset,554b, bOffset,555length, LOG2_ARRAY_DOUBLE_INDEX_SCALE);556}557if (i >= 0) {558// Check if mismatch is not associated with two NaN values559if (!Double.isNaN(a[aFromIndex + i]) || !Double.isNaN(b[bFromIndex + i]))560return i;561562// Mismatch on two different NaN values that are normalized to match563// Fall back to slow mechanism564// ISSUE: Consider looping over vectorizedMismatch adjusting ranges565// However, requires that returned value be relative to input ranges566i++;567for (; i < length; i++) {568if (Double.doubleToLongBits(a[aFromIndex + i]) != Double.doubleToLongBits(b[bFromIndex + i]))569return i;570}571}572573return -1;574}575576/**577* A soft maximum array length imposed by array growth computations.578* Some JVMs (such as HotSpot) have an implementation limit that will cause579*580* OutOfMemoryError("Requested array size exceeds VM limit")581*582* to be thrown if a request is made to allocate an array of some length near583* Integer.MAX_VALUE, even if there is sufficient heap available. The actual584* limit might depend on some JVM implementation-specific characteristics such585* as the object header size. The soft maximum value is chosen conservatively so586* as to be smaller than any implementation limit that is likely to be encountered.587*/588public static final int SOFT_MAX_ARRAY_LENGTH = Integer.MAX_VALUE - 8;589590/**591* Computes a new array length given an array's current length, a minimum growth592* amount, and a preferred growth amount. The computation is done in an overflow-safe593* fashion.594*595* This method is used by objects that contain an array that might need to be grown596* in order to fulfill some immediate need (the minimum growth amount) but would also597* like to request more space (the preferred growth amount) in order to accommodate598* potential future needs. The returned length is usually clamped at the soft maximum599* length in order to avoid hitting the JVM implementation limit. However, the soft600* maximum will be exceeded if the minimum growth amount requires it.601*602* If the preferred growth amount is less than the minimum growth amount, the603* minimum growth amount is used as the preferred growth amount.604*605* The preferred length is determined by adding the preferred growth amount to the606* current length. If the preferred length does not exceed the soft maximum length607* (SOFT_MAX_ARRAY_LENGTH) then the preferred length is returned.608*609* If the preferred length exceeds the soft maximum, we use the minimum growth610* amount. The minimum required length is determined by adding the minimum growth611* amount to the current length. If the minimum required length exceeds Integer.MAX_VALUE,612* then this method throws OutOfMemoryError. Otherwise, this method returns the greater of613* the soft maximum or the minimum required length.614*615* Note that this method does not do any array allocation itself; it only does array616* length growth computations. However, it will throw OutOfMemoryError as noted above.617*618* Note also that this method cannot detect the JVM's implementation limit, and it619* may compute and return a length value up to and including Integer.MAX_VALUE that620* might exceed the JVM's implementation limit. In that case, the caller will likely621* attempt an array allocation with that length and encounter an OutOfMemoryError.622* Of course, regardless of the length value returned from this method, the caller623* may encounter OutOfMemoryError if there is insufficient heap to fulfill the request.624*625* @param oldLength current length of the array (must be nonnegative)626* @param minGrowth minimum required growth amount (must be positive)627* @param prefGrowth preferred growth amount628* @return the new array length629* @throws OutOfMemoryError if the new length would exceed Integer.MAX_VALUE630*/631public static int newLength(int oldLength, int minGrowth, int prefGrowth) {632// preconditions not checked because of inlining633// assert oldLength >= 0634// assert minGrowth > 0635636int prefLength = oldLength + Math.max(minGrowth, prefGrowth); // might overflow637if (0 < prefLength && prefLength <= SOFT_MAX_ARRAY_LENGTH) {638return prefLength;639} else {640// put code cold in a separate method641return hugeLength(oldLength, minGrowth);642}643}644645private static int hugeLength(int oldLength, int minGrowth) {646int minLength = oldLength + minGrowth;647if (minLength < 0) { // overflow648throw new OutOfMemoryError(649"Required array length " + oldLength + " + " + minGrowth + " is too large");650} else if (minLength <= SOFT_MAX_ARRAY_LENGTH) {651return SOFT_MAX_ARRAY_LENGTH;652} else {653return minLength;654}655}656}657658659