1 /* 2 * Copyright (c) 2015, 2017 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 find a mismatch between two primitive arrays. 32 * 33 * <p>Array equality and lexicographical comparison can be built on top of 34 * array mismatch functionality. 35 * 36 * <p>The mismatch method implementation, {@link #vectorizedMismatch}, leverages 37 * vector-based techniques to access and compare the contents of two arrays. 38 * The Java implementation uses {@code Unsafe.getLongUnaligned} to access the 39 * content of an array, thus access is supported on platforms that do not 40 * support unaligned access. For a byte[] array, 8 bytes (64 bits) can be 41 * accessed and compared as a unit rather than individually, which increases 42 * the performance when the method is compiled by the HotSpot VM. On supported 43 * platforms the mismatch implementation is intrinsified to leverage SIMD 44 * instructions. So for a byte[] array, 16 bytes (128 bits), 32 bytes 45 * (256 bits), and perhaps in the future even 64 bytes (512 bits), platform 46 * permitting, can be accessed and compared as a unit, which further increases 47 * the performance over the Java implementation. 48 * 49 * <p>None of the mismatch methods perform array bounds checks. It is the 50 * responsibility of the caller (direct or otherwise) to perform such checks 51 * before calling this method. 52 */ 53 public class ArraysSupport { 54 static final Unsafe U = Unsafe.getUnsafe(); 55 56 private static final boolean BIG_ENDIAN = U.isBigEndian(); 57 58 public static final int LOG2_ARRAY_BOOLEAN_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BOOLEAN_INDEX_SCALE); 59 public static final int LOG2_ARRAY_BYTE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_BYTE_INDEX_SCALE); 60 public static final int LOG2_ARRAY_CHAR_INDEX_SCALE = exactLog2(Unsafe.ARRAY_CHAR_INDEX_SCALE); 61 public static final int LOG2_ARRAY_SHORT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_SHORT_INDEX_SCALE); 62 public static final int LOG2_ARRAY_INT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_INT_INDEX_SCALE); 63 public static final int LOG2_ARRAY_LONG_INDEX_SCALE = exactLog2(Unsafe.ARRAY_LONG_INDEX_SCALE); 64 public static final int LOG2_ARRAY_FLOAT_INDEX_SCALE = exactLog2(Unsafe.ARRAY_FLOAT_INDEX_SCALE); 65 public static final int LOG2_ARRAY_DOUBLE_INDEX_SCALE = exactLog2(Unsafe.ARRAY_DOUBLE_INDEX_SCALE); 66 67 private static final int LOG2_BYTE_BIT_SIZE = exactLog2(Byte.SIZE); 68 69 private static int exactLog2(int scale) { 70 if ((scale & (scale - 1)) != 0) 71 throw new Error("data type scale not a power of two"); 72 return Integer.numberOfTrailingZeros(scale); 73 } 74 75 private ArraysSupport() {} 76 77 /** 78 * Find the relative index of the first mismatching pair of elements in two 79 * primitive arrays of the same component type. Pairs of elements will be 80 * tested in order relative to given offsets into both arrays. 81 * 82 * <p>This method does not perform type checks or bounds checks. It is the 83 * responsibility of the caller to perform such checks before calling this 84 * method. 85 * 86 * <p>The given offsets, in bytes, need not be aligned according to the 87 * given log<sub>2</sub> size the array elements. More specifically, an 88 * offset modulus the size need not be zero. 89 * 90 * @param a the first array to be tested for mismatch, or {@code null} for 91 * direct memory access 92 * @param aOffset the relative offset, in bytes, from the base address of 93 * the first array to test from, otherwise if the first array is 94 * {@code null}, an absolute address pointing to the first element to test. 95 * @param b the second array to be tested for mismatch, or {@code null} for 96 * direct memory access 97 * @param bOffset the relative offset, in bytes, from the base address of 98 * the second array to test from, otherwise if the second array is 99 * {@code null}, an absolute address pointing to the first element to test. 100 * @param length the number of array elements to test 101 * @param log2ArrayIndexScale log<sub>2</sub> of the array index scale, that 102 * corresponds to the size, in bytes, of an array element. 103 * @return if a mismatch is found a relative index, between 0 (inclusive) 104 * and {@code length} (exclusive), of the first mismatching pair of elements 105 * in the two arrays. Otherwise, if a mismatch is not found the bitwise 106 * compliment of the number of remaining pairs of elements to be checked in 107 * the tail of the two arrays. 108 */ 109 @HotSpotIntrinsicCandidate 110 public static int vectorizedMismatch(Object a, long aOffset, 111 Object b, long bOffset, 112 int length, 113 int log2ArrayIndexScale) { 114 // assert a.getClass().isArray(); 115 // assert b.getClass().isArray(); 116 // assert 0 <= length <= sizeOf(a) 117 // assert 0 <= length <= sizeOf(b) 118 // assert 0 <= log2ArrayIndexScale <= 3 119 120 int log2ValuesPerWidth = LOG2_ARRAY_LONG_INDEX_SCALE - log2ArrayIndexScale; 121 int wi = 0; 122 for (; wi < length >> log2ValuesPerWidth; wi++) { 123 long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE; 124 long av = U.getLongUnaligned(a, aOffset + bi); 125 long bv = U.getLongUnaligned(b, bOffset + bi); 126 if (av != bv) { 127 long x = av ^ bv; 128 int o = BIG_ENDIAN 129 ? Long.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale) 130 : Long.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale); 131 return (wi << log2ValuesPerWidth) + o; 132 } 133 } 134 135 // Calculate the tail of remaining elements to check 136 int tail = length - (wi << log2ValuesPerWidth); 137 138 if (log2ArrayIndexScale < LOG2_ARRAY_INT_INDEX_SCALE) { 139 int wordTail = 1 << (LOG2_ARRAY_INT_INDEX_SCALE - log2ArrayIndexScale); 140 // Handle 4 bytes or 2 chars in the tail using int width 141 if (tail >= wordTail) { 142 long bi = ((long) wi) << LOG2_ARRAY_LONG_INDEX_SCALE; 143 int av = U.getIntUnaligned(a, aOffset + bi); 144 int bv = U.getIntUnaligned(b, bOffset + bi); 145 if (av != bv) { 146 int x = av ^ bv; 147 int o = BIG_ENDIAN 148 ? Integer.numberOfLeadingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale) 149 : Integer.numberOfTrailingZeros(x) >> (LOG2_BYTE_BIT_SIZE + log2ArrayIndexScale); 150 return (wi << log2ValuesPerWidth) + o; 151 } 152 tail -= wordTail; 153 } 154 return ~tail; 155 } 156 else { 157 return ~tail; 158 } 159 } 160 161 // Booleans 162 // Each boolean element takes up one byte 163 164 public static int mismatch(boolean[] a, 165 boolean[] b, 166 int length) { 167 int i = 0; 168 if (length > 7) { 169 i = vectorizedMismatch( 170 a, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 171 b, Unsafe.ARRAY_BOOLEAN_BASE_OFFSET, 172 length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE); 173 if (i >= 0) 174 return i; 175 i = length - ~i; 176 } 177 for (; i < length; i++) { 178 if (a[i] != b[i]) 179 return i; 180 } 181 return -1; 182 } 183 184 public static int mismatch(boolean[] a, int aFromIndex, 185 boolean[] b, int bFromIndex, 186 int length) { 187 int i = 0; 188 if (length > 7) { 189 int aOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + aFromIndex; 190 int bOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET + bFromIndex; 191 i = vectorizedMismatch( 192 a, aOffset, 193 b, bOffset, 194 length, LOG2_ARRAY_BOOLEAN_INDEX_SCALE); 195 if (i >= 0) 196 return i; 197 i = length - ~i; 198 } 199 for (; i < length; i++) { 200 if (a[aFromIndex + i] != b[bFromIndex + i]) 201 return i; 202 } 203 return -1; 204 } 205 206 207 // Bytes 208 209 /** 210 * Find the index of a mismatch between two arrays. 211 * 212 * <p>This method does not perform bounds checks. It is the responsibility 213 * of the caller to perform such bounds checks before calling this method. 214 * 215 * @param a the first array to be tested for a mismatch 216 * @param b the second array to be tested for a mismatch 217 * @param length the number of bytes from each array to check 218 * @return the index of a mismatch between the two arrays, otherwise -1 if 219 * no mismatch. The index will be within the range of (inclusive) 0 to 220 * (exclusive) the smaller of the two array lengths. 221 */ 222 public static int mismatch(byte[] a, 223 byte[] b, 224 int length) { 225 // ISSUE: defer to index receiving methods if performance is good 226 // assert length <= a.length 227 // assert length <= b.length 228 229 int i = 0; 230 if (length > 7) { 231 i = vectorizedMismatch( 232 a, Unsafe.ARRAY_BYTE_BASE_OFFSET, 233 b, Unsafe.ARRAY_BYTE_BASE_OFFSET, 234 length, LOG2_ARRAY_BYTE_INDEX_SCALE); 235 if (i >= 0) 236 return i; 237 // Align to tail 238 i = length - ~i; 239 // assert i >= 0 && i <= 7; 240 } 241 // Tail < 8 bytes 242 for (; i < length; i++) { 243 if (a[i] != b[i]) 244 return i; 245 } 246 return -1; 247 } 248 249 /** 250 * Find the relative index of a mismatch between two arrays starting from 251 * given indexes. 252 * 253 * <p>This method does not perform bounds checks. It is the responsibility 254 * of the caller to perform such bounds checks before calling this method. 255 * 256 * @param a the first array to be tested for a mismatch 257 * @param aFromIndex the index of the first element (inclusive) in the first 258 * array to be compared 259 * @param b the second array to be tested for a mismatch 260 * @param bFromIndex the index of the first element (inclusive) in the 261 * second array to be compared 262 * @param length the number of bytes from each array to check 263 * @return the relative index of a mismatch between the two arrays, 264 * otherwise -1 if no mismatch. The index will be within the range of 265 * (inclusive) 0 to (exclusive) the smaller of the two array bounds. 266 */ 267 public static int mismatch(byte[] a, int aFromIndex, 268 byte[] b, int bFromIndex, 269 int length) { 270 // assert 0 <= aFromIndex < a.length 271 // assert 0 <= aFromIndex + length <= a.length 272 // assert 0 <= bFromIndex < b.length 273 // assert 0 <= bFromIndex + length <= b.length 274 // assert length >= 0 275 276 int i = 0; 277 if (length > 7) { 278 int aOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + aFromIndex; 279 int bOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET + bFromIndex; 280 i = vectorizedMismatch( 281 a, aOffset, 282 b, bOffset, 283 length, LOG2_ARRAY_BYTE_INDEX_SCALE); 284 if (i >= 0) 285 return i; 286 i = length - ~i; 287 } 288 for (; i < length; i++) { 289 if (a[aFromIndex + i] != b[bFromIndex + i]) 290 return i; 291 } 292 return -1; 293 } 294 295 296 // Chars 297 298 public static int mismatch(char[] a, 299 char[] b, 300 int length) { 301 int i = 0; 302 if (length > 3) { 303 i = vectorizedMismatch( 304 a, Unsafe.ARRAY_CHAR_BASE_OFFSET, 305 b, Unsafe.ARRAY_CHAR_BASE_OFFSET, 306 length, LOG2_ARRAY_CHAR_INDEX_SCALE); 307 if (i >= 0) 308 return i; 309 i = length - ~i; 310 } 311 for (; i < length; i++) { 312 if (a[i] != b[i]) 313 return i; 314 } 315 return -1; 316 } 317 318 public static int mismatch(char[] a, int aFromIndex, 319 char[] b, int bFromIndex, 320 int length) { 321 int i = 0; 322 if (length > 3) { 323 int aOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE); 324 int bOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_CHAR_INDEX_SCALE); 325 i = vectorizedMismatch( 326 a, aOffset, 327 b, bOffset, 328 length, LOG2_ARRAY_CHAR_INDEX_SCALE); 329 if (i >= 0) 330 return i; 331 i = length - ~i; 332 } 333 for (; i < length; i++) { 334 if (a[aFromIndex + i] != b[bFromIndex + i]) 335 return i; 336 } 337 return -1; 338 } 339 340 341 // Shorts 342 343 public static int mismatch(short[] a, 344 short[] b, 345 int length) { 346 int i = 0; 347 if (length > 3) { 348 i = vectorizedMismatch( 349 a, Unsafe.ARRAY_SHORT_BASE_OFFSET, 350 b, Unsafe.ARRAY_SHORT_BASE_OFFSET, 351 length, LOG2_ARRAY_SHORT_INDEX_SCALE); 352 if (i >= 0) 353 return i; 354 i = length - ~i; 355 } 356 for (; i < length; i++) { 357 if (a[i] != b[i]) 358 return i; 359 } 360 return -1; 361 } 362 363 public static int mismatch(short[] a, int aFromIndex, 364 short[] b, int bFromIndex, 365 int length) { 366 int i = 0; 367 if (length > 3) { 368 int aOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE); 369 int bOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_SHORT_INDEX_SCALE); 370 i = vectorizedMismatch( 371 a, aOffset, 372 b, bOffset, 373 length, LOG2_ARRAY_SHORT_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 // Ints 387 388 public static int mismatch(int[] a, 389 int[] b, 390 int length) { 391 int i = 0; 392 if (length > 1) { 393 i = vectorizedMismatch( 394 a, Unsafe.ARRAY_INT_BASE_OFFSET, 395 b, Unsafe.ARRAY_INT_BASE_OFFSET, 396 length, LOG2_ARRAY_INT_INDEX_SCALE); 397 if (i >= 0) 398 return i; 399 i = length - ~i; 400 } 401 for (; i < length; i++) { 402 if (a[i] != b[i]) 403 return i; 404 } 405 return -1; 406 } 407 408 public static int mismatch(int[] a, int aFromIndex, 409 int[] b, int bFromIndex, 410 int length) { 411 int i = 0; 412 if (length > 1) { 413 int aOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_INT_INDEX_SCALE); 414 int bOffset = Unsafe.ARRAY_INT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_INT_INDEX_SCALE); 415 i = vectorizedMismatch( 416 a, aOffset, 417 b, bOffset, 418 length, LOG2_ARRAY_INT_INDEX_SCALE); 419 if (i >= 0) 420 return i; 421 i = length - ~i; 422 } 423 for (; i < length; i++) { 424 if (a[aFromIndex + i] != b[bFromIndex + i]) 425 return i; 426 } 427 return -1; 428 } 429 430 431 // Floats 432 433 public static int mismatch(float[] a, 434 float[] b, 435 int length) { 436 return mismatch(a, 0, b, 0, length); 437 } 438 439 public static int mismatch(float[] a, int aFromIndex, 440 float[] b, int bFromIndex, 441 int length) { 442 int i = 0; 443 if (length > 1) { 444 int aOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE); 445 int bOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_FLOAT_INDEX_SCALE); 446 i = vectorizedMismatch( 447 a, aOffset, 448 b, bOffset, 449 length, LOG2_ARRAY_FLOAT_INDEX_SCALE); 450 // Mismatched 451 if (i >= 0) { 452 // Check if mismatch is not associated with two NaN values 453 if (!Float.isNaN(a[aFromIndex + i]) || !Float.isNaN(b[bFromIndex + i])) 454 return i; 455 456 // Mismatch on two different NaN values that are normalized to match 457 // Fall back to slow mechanism 458 // ISSUE: Consider looping over vectorizedMismatch adjusting ranges 459 // However, requires that returned value be relative to input ranges 460 i++; 461 } 462 // Matched 463 else { 464 i = length - ~i; 465 } 466 } 467 for (; i < length; i++) { 468 if (Float.floatToIntBits(a[aFromIndex + i]) != Float.floatToIntBits(b[bFromIndex + i])) 469 return i; 470 } 471 return -1; 472 } 473 474 // 64 bit sizes 475 476 // Long 477 478 public static int mismatch(long[] a, 479 long[] b, 480 int length) { 481 if (length == 0) { 482 return -1; 483 } 484 int i = vectorizedMismatch( 485 a, Unsafe.ARRAY_LONG_BASE_OFFSET, 486 b, Unsafe.ARRAY_LONG_BASE_OFFSET, 487 length, LOG2_ARRAY_LONG_INDEX_SCALE); 488 return i >= 0 ? i : -1; 489 } 490 491 public static int mismatch(long[] a, int aFromIndex, 492 long[] b, int bFromIndex, 493 int length) { 494 if (length == 0) { 495 return -1; 496 } 497 int aOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE); 498 int bOffset = Unsafe.ARRAY_LONG_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_LONG_INDEX_SCALE); 499 int i = vectorizedMismatch( 500 a, aOffset, 501 b, bOffset, 502 length, LOG2_ARRAY_LONG_INDEX_SCALE); 503 return i >= 0 ? i : -1; 504 } 505 506 507 // Double 508 509 public static int mismatch(double[] a, 510 double[] b, 511 int length) { 512 return mismatch(a, 0, b, 0, length); 513 } 514 515 public static int mismatch(double[] a, int aFromIndex, 516 double[] b, int bFromIndex, 517 int length) { 518 if (length == 0) { 519 return -1; 520 } 521 int aOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (aFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE); 522 int bOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET + (bFromIndex << LOG2_ARRAY_DOUBLE_INDEX_SCALE); 523 int i = vectorizedMismatch( 524 a, aOffset, 525 b, bOffset, 526 length, LOG2_ARRAY_DOUBLE_INDEX_SCALE); 527 if (i >= 0) { 528 // Check if mismatch is not associated with two NaN values 529 if (!Double.isNaN(a[aFromIndex + i]) || !Double.isNaN(b[bFromIndex + i])) 530 return i; 531 532 // Mismatch on two different NaN values that are normalized to match 533 // Fall back to slow mechanism 534 // ISSUE: Consider looping over vectorizedMismatch adjusting ranges 535 // However, requires that returned value be relative to input ranges 536 i++; 537 for (; i < length; i++) { 538 if (Double.doubleToLongBits(a[aFromIndex + i]) != Double.doubleToLongBits(b[bFromIndex + i])) 539 return i; 540 } 541 } 542 543 return -1; 544 } 545 }