Coverage Summary for Class: LittleEndianByteArray (com.google.common.hash)

Class Method, % Line, %
LittleEndianByteArray 0% (0/7) 0% (0/22)
LittleEndianByteArray$JavaLittleEndianBytes 0% (0/1) 0% (0/2)
LittleEndianByteArray$JavaLittleEndianBytes$1 0% (0/3) 0% (0/5)
LittleEndianByteArray$UnsafeByteArray 0% (0/2) 0% (0/12)
LittleEndianByteArray$UnsafeByteArray$1 0% (0/3) 0% (0/3)
LittleEndianByteArray$UnsafeByteArray$2 0% (0/3) 0% (0/5)
LittleEndianByteArray$UnsafeByteArray$3 0% (0/2) 0% (0/8)
Total 0% (0/21) 0% (0/57)


1 /* 2  * Copyright (C) 2015 The Guava Authors 3  * 4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5  * in compliance with the License. You may obtain a copy of the License at 6  * 7  * http://www.apache.org/licenses/LICENSE-2.0 8  * 9  * Unless required by applicable law or agreed to in writing, software distributed under the License 10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 11  * or implied. See the License for the specific language governing permissions and limitations under 12  * the License. 13  */ 14  15 package com.google.common.hash; 16  17 import com.google.common.primitives.Longs; 18 import java.nio.ByteOrder; 19 import sun.misc.Unsafe; 20  21 /** 22  * Utility functions for loading and storing values from a byte array. 23  * 24  * @author Kevin Damm 25  * @author Kyle Maddison 26  */ 27 @ElementTypesAreNonnullByDefault 28 final class LittleEndianByteArray { 29  30  /** The instance that actually does the work; delegates to Unsafe or a pure-Java fallback. */ 31  private static final LittleEndianBytes byteArray; 32  33  /** 34  * Load 8 bytes into long in a little endian manner, from the substring between position and 35  * position + 8. The array must have at least 8 bytes from offset (inclusive). 36  * 37  * @param input the input bytes 38  * @param offset the offset into the array at which to start 39  * @return a long of a concatenated 8 bytes 40  */ 41  static long load64(byte[] input, int offset) { 42  // We don't want this in production code as this is the most critical part of the loop. 43  assert input.length >= offset + 8; 44  // Delegates to the fast (unsafe) version or the fallback. 45  return byteArray.getLongLittleEndian(input, offset); 46  } 47  48  /** 49  * Similar to load64, but allows offset + 8 > input.length, padding the result with zeroes. This 50  * has to explicitly reverse the order of the bytes as it packs them into the result which makes 51  * it slower than the native version. 52  * 53  * @param input the input bytes 54  * @param offset the offset into the array at which to start reading 55  * @param length the number of bytes from the input to read 56  * @return a long of a concatenated 8 bytes 57  */ 58  static long load64Safely(byte[] input, int offset, int length) { 59  long result = 0; 60  // Due to the way we shift, we can stop iterating once we've run out of data, the rest 61  // of the result already being filled with zeros. 62  63  // This loop is critical to performance, so please check HashBenchmark if altering it. 64  int limit = Math.min(length, 8); 65  for (int i = 0; i < limit; i++) { 66  // Shift value left while iterating logically through the array. 67  result |= (input[offset + i] & 0xFFL) << (i * 8); 68  } 69  return result; 70  } 71  72  /** 73  * Store 8 bytes into the provided array at the indicated offset, using the value provided. 74  * 75  * @param sink the output byte array 76  * @param offset the offset into the array at which to start writing 77  * @param value the value to write 78  */ 79  static void store64(byte[] sink, int offset, long value) { 80  // We don't want to assert in production code. 81  assert offset >= 0 && offset + 8 <= sink.length; 82  // Delegates to the fast (unsafe)version or the fallback. 83  byteArray.putLongLittleEndian(sink, offset, value); 84  } 85  86  /** 87  * Load 4 bytes from the provided array at the indicated offset. 88  * 89  * @param source the input bytes 90  * @param offset the offset into the array at which to start 91  * @return the value found in the array in the form of a long 92  */ 93  static int load32(byte[] source, int offset) { 94  // TODO(user): Measure the benefit of delegating this to LittleEndianBytes also. 95  return (source[offset] & 0xFF) 96  | ((source[offset + 1] & 0xFF) << 8) 97  | ((source[offset + 2] & 0xFF) << 16) 98  | ((source[offset + 3] & 0xFF) << 24); 99  } 100  101  /** 102  * Indicates that the loading of Unsafe was successful and the load and store operations will be 103  * very efficient. May be useful for calling code to fall back on an alternative implementation 104  * that is slower than Unsafe.get/store but faster than the pure-Java mask-and-shift. 105  */ 106  static boolean usingUnsafe() { 107  return (byteArray instanceof UnsafeByteArray); 108  } 109  110  /** 111  * Common interface for retrieving a 64-bit long from a little-endian byte array. 112  * 113  * <p>This abstraction allows us to use single-instruction load and put when available, or fall 114  * back on the slower approach of using Longs.fromBytes(byte...). 115  */ 116  private interface LittleEndianBytes { 117  long getLongLittleEndian(byte[] array, int offset); 118  119  void putLongLittleEndian(byte[] array, int offset, long value); 120  } 121  122  /** 123  * The only reference to Unsafe is in this nested class. We set things up so that if 124  * Unsafe.theUnsafe is inaccessible, the attempt to load the nested class fails, and the outer 125  * class's static initializer can fall back on a non-Unsafe version. 126  */ 127  private enum UnsafeByteArray implements LittleEndianBytes { 128  // Do *not* change the order of these constants! 129  UNSAFE_LITTLE_ENDIAN { 130  @Override 131  public long getLongLittleEndian(byte[] array, int offset) { 132  return theUnsafe.getLong(array, (long) offset + BYTE_ARRAY_BASE_OFFSET); 133  } 134  135  @Override 136  public void putLongLittleEndian(byte[] array, int offset, long value) { 137  theUnsafe.putLong(array, (long) offset + BYTE_ARRAY_BASE_OFFSET, value); 138  } 139  }, 140  UNSAFE_BIG_ENDIAN { 141  @Override 142  public long getLongLittleEndian(byte[] array, int offset) { 143  long bigEndian = theUnsafe.getLong(array, (long) offset + BYTE_ARRAY_BASE_OFFSET); 144  // The hardware is big-endian, so we need to reverse the order of the bytes. 145  return Long.reverseBytes(bigEndian); 146  } 147  148  @Override 149  public void putLongLittleEndian(byte[] array, int offset, long value) { 150  // Reverse the order of the bytes before storing, since we're on big-endian hardware. 151  long littleEndianValue = Long.reverseBytes(value); 152  theUnsafe.putLong(array, (long) offset + BYTE_ARRAY_BASE_OFFSET, littleEndianValue); 153  } 154  }; 155  156  // Provides load and store operations that use native instructions to get better performance. 157  private static final Unsafe theUnsafe; 158  159  // The offset to the first element in a byte array. 160  private static final int BYTE_ARRAY_BASE_OFFSET; 161  162  /** 163  * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package. Replace with a simple 164  * call to Unsafe.getUnsafe when integrating into a jdk. 165  * 166  * @return a sun.misc.Unsafe instance if successful 167  */ 168  private static sun.misc.Unsafe getUnsafe() { 169  try { 170  return sun.misc.Unsafe.getUnsafe(); 171  } catch (SecurityException tryReflectionInstead) { 172  // We'll try reflection instead. 173  } 174  try { 175  return java.security.AccessController.doPrivileged( 176  new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() { 177  @Override 178  public sun.misc.Unsafe run() throws Exception { 179  Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class; 180  for (java.lang.reflect.Field f : k.getDeclaredFields()) { 181  f.setAccessible(true); 182  Object x = f.get(null); 183  if (k.isInstance(x)) { 184  return k.cast(x); 185  } 186  } 187  throw new NoSuchFieldError("the Unsafe"); 188  } 189  }); 190  } catch (java.security.PrivilegedActionException e) { 191  throw new RuntimeException("Could not initialize intrinsics", e.getCause()); 192  } 193  } 194  195  static { 196  theUnsafe = getUnsafe(); 197  BYTE_ARRAY_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class); 198  199  // sanity check - this should never fail 200  if (theUnsafe.arrayIndexScale(byte[].class) != 1) { 201  throw new AssertionError(); 202  } 203  } 204  } 205  206  /** Fallback implementation for when Unsafe is not available in our current environment. */ 207  private enum JavaLittleEndianBytes implements LittleEndianBytes { 208  INSTANCE { 209  @Override 210  public long getLongLittleEndian(byte[] source, int offset) { 211  return Longs.fromBytes( 212  source[offset + 7], 213  source[offset + 6], 214  source[offset + 5], 215  source[offset + 4], 216  source[offset + 3], 217  source[offset + 2], 218  source[offset + 1], 219  source[offset]); 220  } 221  222  @Override 223  public void putLongLittleEndian(byte[] sink, int offset, long value) { 224  long mask = 0xFFL; 225  for (int i = 0; i < 8; mask <<= 8, i++) { 226  sink[offset + i] = (byte) ((value & mask) >> (i * 8)); 227  } 228  } 229  }; 230  } 231  232  static { 233  LittleEndianBytes theGetter = JavaLittleEndianBytes.INSTANCE; 234  try { 235  /* 236  * UnsafeByteArray uses Unsafe.getLong() in an unsupported way, which is known to cause 237  * crashes on Android when running in 32-bit mode. For maximum safety, we shouldn't use 238  * Unsafe.getLong() at all, but the performance benefit on x86_64 is too great to ignore, so 239  * as a compromise, we enable the optimization only on platforms that we specifically know to 240  * work. 241  * 242  * In the future, the use of Unsafe.getLong() should be replaced by ByteBuffer.getLong(), 243  * which will have an efficient native implementation in JDK 9. 244  * 245  */ 246  final String arch = System.getProperty("os.arch"); 247  if ("amd64".equals(arch)) { 248  theGetter = 249  ByteOrder.nativeOrder().equals(ByteOrder.LITTLE_ENDIAN) 250  ? UnsafeByteArray.UNSAFE_LITTLE_ENDIAN 251  : UnsafeByteArray.UNSAFE_BIG_ENDIAN; 252  } 253  } catch (Throwable t) { 254  // ensure we really catch *everything* 255  } 256  byteArray = theGetter; 257  } 258  259  /** Deter instantiation of this class. */ 260  private LittleEndianByteArray() {} 261 }