• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
33 import java.lang.reflect.Field;
34 import java.nio.Buffer;
35 import java.nio.ByteBuffer;
36 import java.nio.ByteOrder;
37 import java.security.AccessController;
38 import java.security.PrivilegedExceptionAction;
39 import java.util.logging.Level;
40 import java.util.logging.Logger;
41 
42 /** Utility class for working with unsafe operations. */
43 final class UnsafeUtil {
44   private static final sun.misc.Unsafe UNSAFE = getUnsafe();
45   private static final Class<?> MEMORY_CLASS = Android.getMemoryClass();
46   private static final boolean IS_ANDROID_64 = determineAndroidSupportByAddressSize(long.class);
47   private static final boolean IS_ANDROID_32 = determineAndroidSupportByAddressSize(int.class);
48   private static final MemoryAccessor MEMORY_ACCESSOR = getMemoryAccessor();
49   private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
50       supportsUnsafeByteBufferOperations();
51   private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
52 
53   static final long BYTE_ARRAY_BASE_OFFSET = arrayBaseOffset(byte[].class);
54   // Micro-optimization: we can assume a scale of 1 and skip the multiply
55   // private static final long BYTE_ARRAY_INDEX_SCALE = 1;
56 
57   private static final long BOOLEAN_ARRAY_BASE_OFFSET = arrayBaseOffset(boolean[].class);
58   private static final long BOOLEAN_ARRAY_INDEX_SCALE = arrayIndexScale(boolean[].class);
59 
60   private static final long INT_ARRAY_BASE_OFFSET = arrayBaseOffset(int[].class);
61   private static final long INT_ARRAY_INDEX_SCALE = arrayIndexScale(int[].class);
62 
63   private static final long LONG_ARRAY_BASE_OFFSET = arrayBaseOffset(long[].class);
64   private static final long LONG_ARRAY_INDEX_SCALE = arrayIndexScale(long[].class);
65 
66   private static final long FLOAT_ARRAY_BASE_OFFSET = arrayBaseOffset(float[].class);
67   private static final long FLOAT_ARRAY_INDEX_SCALE = arrayIndexScale(float[].class);
68 
69   private static final long DOUBLE_ARRAY_BASE_OFFSET = arrayBaseOffset(double[].class);
70   private static final long DOUBLE_ARRAY_INDEX_SCALE = arrayIndexScale(double[].class);
71 
72   private static final long OBJECT_ARRAY_BASE_OFFSET = arrayBaseOffset(Object[].class);
73   private static final long OBJECT_ARRAY_INDEX_SCALE = arrayIndexScale(Object[].class);
74 
75   private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField());
76 
77   private static final int STRIDE = 8;
78   private static final int STRIDE_ALIGNMENT_MASK = STRIDE - 1;
79   private static final int BYTE_ARRAY_ALIGNMENT =
80       (int) (BYTE_ARRAY_BASE_OFFSET & STRIDE_ALIGNMENT_MASK);
81 
82   static final boolean IS_BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
83 
UnsafeUtil()84   private UnsafeUtil() {}
85 
hasUnsafeArrayOperations()86   static boolean hasUnsafeArrayOperations() {
87     return HAS_UNSAFE_ARRAY_OPERATIONS;
88   }
89 
hasUnsafeByteBufferOperations()90   static boolean hasUnsafeByteBufferOperations() {
91     return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
92   }
93 
isAndroid64()94   static boolean isAndroid64() {
95     return IS_ANDROID_64;
96   }
97 
98   @SuppressWarnings("unchecked") // safe by method contract
allocateInstance(Class<T> clazz)99   static <T> T allocateInstance(Class<T> clazz) {
100     try {
101       return (T) UNSAFE.allocateInstance(clazz);
102     } catch (InstantiationException e) {
103       throw new IllegalStateException(e);
104     }
105   }
106 
objectFieldOffset(Field field)107   static long objectFieldOffset(Field field) {
108     return MEMORY_ACCESSOR.objectFieldOffset(field);
109   }
110 
arrayBaseOffset(Class<?> clazz)111   private static int arrayBaseOffset(Class<?> clazz) {
112     return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(clazz) : -1;
113   }
114 
arrayIndexScale(Class<?> clazz)115   private static int arrayIndexScale(Class<?> clazz) {
116     return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayIndexScale(clazz) : -1;
117   }
118 
getByte(Object target, long offset)119   static byte getByte(Object target, long offset) {
120     return MEMORY_ACCESSOR.getByte(target, offset);
121   }
122 
putByte(Object target, long offset, byte value)123   static void putByte(Object target, long offset, byte value) {
124     MEMORY_ACCESSOR.putByte(target, offset, value);
125   }
126 
getInt(Object target, long offset)127   static int getInt(Object target, long offset) {
128     return MEMORY_ACCESSOR.getInt(target, offset);
129   }
130 
putInt(Object target, long offset, int value)131   static void putInt(Object target, long offset, int value) {
132     MEMORY_ACCESSOR.putInt(target, offset, value);
133   }
134 
getLong(Object target, long offset)135   static long getLong(Object target, long offset) {
136     return MEMORY_ACCESSOR.getLong(target, offset);
137   }
138 
putLong(Object target, long offset, long value)139   static void putLong(Object target, long offset, long value) {
140     MEMORY_ACCESSOR.putLong(target, offset, value);
141   }
142 
getBoolean(Object target, long offset)143   static boolean getBoolean(Object target, long offset) {
144     return MEMORY_ACCESSOR.getBoolean(target, offset);
145   }
146 
putBoolean(Object target, long offset, boolean value)147   static void putBoolean(Object target, long offset, boolean value) {
148     MEMORY_ACCESSOR.putBoolean(target, offset, value);
149   }
150 
getFloat(Object target, long offset)151   static float getFloat(Object target, long offset) {
152     return MEMORY_ACCESSOR.getFloat(target, offset);
153   }
154 
putFloat(Object target, long offset, float value)155   static void putFloat(Object target, long offset, float value) {
156     MEMORY_ACCESSOR.putFloat(target, offset, value);
157   }
158 
getDouble(Object target, long offset)159   static double getDouble(Object target, long offset) {
160     return MEMORY_ACCESSOR.getDouble(target, offset);
161   }
162 
putDouble(Object target, long offset, double value)163   static void putDouble(Object target, long offset, double value) {
164     MEMORY_ACCESSOR.putDouble(target, offset, value);
165   }
166 
getObject(Object target, long offset)167   static Object getObject(Object target, long offset) {
168     return MEMORY_ACCESSOR.getObject(target, offset);
169   }
170 
putObject(Object target, long offset, Object value)171   static void putObject(Object target, long offset, Object value) {
172     MEMORY_ACCESSOR.putObject(target, offset, value);
173   }
174 
getByte(byte[] target, long index)175   static byte getByte(byte[] target, long index) {
176     return MEMORY_ACCESSOR.getByte(target, BYTE_ARRAY_BASE_OFFSET + index);
177   }
178 
putByte(byte[] target, long index, byte value)179   static void putByte(byte[] target, long index, byte value) {
180     MEMORY_ACCESSOR.putByte(target, BYTE_ARRAY_BASE_OFFSET + index, value);
181   }
182 
getInt(int[] target, long index)183   static int getInt(int[] target, long index) {
184     return MEMORY_ACCESSOR.getInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE));
185   }
186 
putInt(int[] target, long index, int value)187   static void putInt(int[] target, long index, int value) {
188     MEMORY_ACCESSOR.putInt(target, INT_ARRAY_BASE_OFFSET + (index * INT_ARRAY_INDEX_SCALE), value);
189   }
190 
getLong(long[] target, long index)191   static long getLong(long[] target, long index) {
192     return MEMORY_ACCESSOR.getLong(
193         target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE));
194   }
195 
putLong(long[] target, long index, long value)196   static void putLong(long[] target, long index, long value) {
197     MEMORY_ACCESSOR.putLong(
198         target, LONG_ARRAY_BASE_OFFSET + (index * LONG_ARRAY_INDEX_SCALE), value);
199   }
200 
getBoolean(boolean[] target, long index)201   static boolean getBoolean(boolean[] target, long index) {
202     return MEMORY_ACCESSOR.getBoolean(
203         target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE));
204   }
205 
putBoolean(boolean[] target, long index, boolean value)206   static void putBoolean(boolean[] target, long index, boolean value) {
207     MEMORY_ACCESSOR.putBoolean(
208         target, BOOLEAN_ARRAY_BASE_OFFSET + (index * BOOLEAN_ARRAY_INDEX_SCALE), value);
209   }
210 
getFloat(float[] target, long index)211   static float getFloat(float[] target, long index) {
212     return MEMORY_ACCESSOR.getFloat(
213         target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE));
214   }
215 
putFloat(float[] target, long index, float value)216   static void putFloat(float[] target, long index, float value) {
217     MEMORY_ACCESSOR.putFloat(
218         target, FLOAT_ARRAY_BASE_OFFSET + (index * FLOAT_ARRAY_INDEX_SCALE), value);
219   }
220 
getDouble(double[] target, long index)221   static double getDouble(double[] target, long index) {
222     return MEMORY_ACCESSOR.getDouble(
223         target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE));
224   }
225 
putDouble(double[] target, long index, double value)226   static void putDouble(double[] target, long index, double value) {
227     MEMORY_ACCESSOR.putDouble(
228         target, DOUBLE_ARRAY_BASE_OFFSET + (index * DOUBLE_ARRAY_INDEX_SCALE), value);
229   }
230 
getObject(Object[] target, long index)231   static Object getObject(Object[] target, long index) {
232     return MEMORY_ACCESSOR.getObject(
233         target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE));
234   }
235 
putObject(Object[] target, long index, Object value)236   static void putObject(Object[] target, long index, Object value) {
237     MEMORY_ACCESSOR.putObject(
238         target, OBJECT_ARRAY_BASE_OFFSET + (index * OBJECT_ARRAY_INDEX_SCALE), value);
239   }
240 
copyMemory(byte[] src, long srcIndex, long targetOffset, long length)241   static void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
242     MEMORY_ACCESSOR.copyMemory(src, srcIndex, targetOffset, length);
243   }
244 
copyMemory(long srcOffset, byte[] target, long targetIndex, long length)245   static void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
246     MEMORY_ACCESSOR.copyMemory(srcOffset, target, targetIndex, length);
247   }
248 
copyMemory(byte[] src, long srcIndex, byte[] target, long targetIndex, long length)249   static void copyMemory(byte[] src, long srcIndex, byte[] target, long targetIndex, long length) {
250     System.arraycopy(src, (int) srcIndex, target, (int) targetIndex, (int) length);
251   }
252 
getByte(long address)253   static byte getByte(long address) {
254     return MEMORY_ACCESSOR.getByte(address);
255   }
256 
putByte(long address, byte value)257   static void putByte(long address, byte value) {
258     MEMORY_ACCESSOR.putByte(address, value);
259   }
260 
getInt(long address)261   static int getInt(long address) {
262     return MEMORY_ACCESSOR.getInt(address);
263   }
264 
putInt(long address, int value)265   static void putInt(long address, int value) {
266     MEMORY_ACCESSOR.putInt(address, value);
267   }
268 
getLong(long address)269   static long getLong(long address) {
270     return MEMORY_ACCESSOR.getLong(address);
271   }
272 
putLong(long address, long value)273   static void putLong(long address, long value) {
274     MEMORY_ACCESSOR.putLong(address, value);
275   }
276 
277   /** Gets the offset of the {@code address} field of the given direct {@link ByteBuffer}. */
addressOffset(ByteBuffer buffer)278   static long addressOffset(ByteBuffer buffer) {
279     return MEMORY_ACCESSOR.getLong(buffer, BUFFER_ADDRESS_OFFSET);
280   }
281 
getStaticObject(Field field)282   static Object getStaticObject(Field field) {
283     return MEMORY_ACCESSOR.getStaticObject(field);
284   }
285 
286   /**
287    * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available on this platform.
288    */
getUnsafe()289   static sun.misc.Unsafe getUnsafe() {
290     sun.misc.Unsafe unsafe = null;
291     try {
292       unsafe =
293           AccessController.doPrivileged(
294               new PrivilegedExceptionAction<sun.misc.Unsafe>() {
295                 @Override
296                 public sun.misc.Unsafe run() throws Exception {
297                   Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
298 
299                   for (Field f : k.getDeclaredFields()) {
300                     f.setAccessible(true);
301                     Object x = f.get(null);
302                     if (k.isInstance(x)) {
303                       return k.cast(x);
304                     }
305                   }
306                   // The sun.misc.Unsafe field does not exist.
307                   return null;
308                 }
309               });
310     } catch (Throwable e) {
311       // Catching Throwable here due to the fact that Google AppEngine raises NoClassDefFoundError
312       // for Unsafe.
313     }
314     return unsafe;
315   }
316 
317   /** Get a {@link MemoryAccessor} appropriate for the platform, or null if not supported. */
getMemoryAccessor()318   private static MemoryAccessor getMemoryAccessor() {
319     if (UNSAFE == null) {
320       return null;
321     }
322     if (Android.isOnAndroidDevice()) {
323       if (IS_ANDROID_64) {
324         return new Android64MemoryAccessor(UNSAFE);
325       } else if (IS_ANDROID_32) {
326         return new Android32MemoryAccessor(UNSAFE);
327       } else {
328         return null;
329       }
330     }
331 
332     return new JvmMemoryAccessor(UNSAFE);
333   }
334 
335   /** Indicates whether or not unsafe array operations are supported on this platform. */
supportsUnsafeArrayOperations()336   private static boolean supportsUnsafeArrayOperations() {
337     if (UNSAFE == null) {
338       return false;
339     }
340     try {
341       Class<?> clazz = UNSAFE.getClass();
342       clazz.getMethod("objectFieldOffset", Field.class);
343       clazz.getMethod("arrayBaseOffset", Class.class);
344       clazz.getMethod("arrayIndexScale", Class.class);
345       clazz.getMethod("getInt", Object.class, long.class);
346       clazz.getMethod("putInt", Object.class, long.class, int.class);
347       clazz.getMethod("getLong", Object.class, long.class);
348       clazz.getMethod("putLong", Object.class, long.class, long.class);
349       clazz.getMethod("getObject", Object.class, long.class);
350       clazz.getMethod("putObject", Object.class, long.class, Object.class);
351       if (Android.isOnAndroidDevice()) {
352         return true;
353       }
354       clazz.getMethod("getByte", Object.class, long.class);
355       clazz.getMethod("putByte", Object.class, long.class, byte.class);
356       clazz.getMethod("getBoolean", Object.class, long.class);
357       clazz.getMethod("putBoolean", Object.class, long.class, boolean.class);
358       clazz.getMethod("getFloat", Object.class, long.class);
359       clazz.getMethod("putFloat", Object.class, long.class, float.class);
360       clazz.getMethod("getDouble", Object.class, long.class);
361       clazz.getMethod("putDouble", Object.class, long.class, double.class);
362 
363       return true;
364     } catch (Throwable e) {
365       // Because log statements are fairly sparse in this class, this logger is initialized
366       // non-statically. Static initialization adds undue runtime costs to the first client to
367       // initialize this class.
368       Logger.getLogger(UnsafeUtil.class.getName())
369           .log(
370               Level.WARNING,
371               "platform method missing - proto runtime falling back to safer methods: " + e);
372     }
373     return false;
374   }
375 
supportsUnsafeByteBufferOperations()376   private static boolean supportsUnsafeByteBufferOperations() {
377     if (UNSAFE == null) {
378       return false;
379     }
380     try {
381       Class<?> clazz = UNSAFE.getClass();
382       // Methods for getting direct buffer address.
383       clazz.getMethod("objectFieldOffset", Field.class);
384       clazz.getMethod("getLong", Object.class, long.class);
385 
386       if (bufferAddressField() == null) {
387         return false;
388       }
389 
390       if (Android.isOnAndroidDevice()) {
391         return true;
392       }
393       clazz.getMethod("getByte", long.class);
394       clazz.getMethod("putByte", long.class, byte.class);
395       clazz.getMethod("getInt", long.class);
396       clazz.getMethod("putInt", long.class, int.class);
397       clazz.getMethod("getLong", long.class);
398       clazz.getMethod("putLong", long.class, long.class);
399       clazz.getMethod("copyMemory", long.class, long.class, long.class);
400       clazz.getMethod("copyMemory", Object.class, long.class, Object.class, long.class, long.class);
401       return true;
402     } catch (Throwable e) {
403       // Because log statements are fairly sparse in this class, this logger is initialized
404       // non-statically. Static initialization adds undue runtime costs to the first client to
405       // initialize this class.
406       Logger.getLogger(UnsafeUtil.class.getName())
407           .log(
408               Level.WARNING,
409               "platform method missing - proto runtime falling back to safer methods: " + e);
410     }
411     return false;
412   }
413 
determineAndroidSupportByAddressSize(Class<?> addressClass)414   private static boolean determineAndroidSupportByAddressSize(Class<?> addressClass) {
415     if (!Android.isOnAndroidDevice()) {
416       return false;
417     }
418     try {
419       Class<?> clazz = MEMORY_CLASS;
420       clazz.getMethod("peekLong", addressClass, boolean.class);
421       clazz.getMethod("pokeLong", addressClass, long.class, boolean.class);
422       clazz.getMethod("pokeInt", addressClass, int.class, boolean.class);
423       clazz.getMethod("peekInt", addressClass, boolean.class);
424       clazz.getMethod("pokeByte", addressClass, byte.class);
425       clazz.getMethod("peekByte", addressClass);
426       clazz.getMethod("pokeByteArray", addressClass, byte[].class, int.class, int.class);
427       clazz.getMethod("peekByteArray", addressClass, byte[].class, int.class, int.class);
428       return true;
429     } catch (Throwable t) {
430       return false;
431     }
432   }
433 
434   /** Finds the address field within a direct {@link Buffer}. */
bufferAddressField()435   private static Field bufferAddressField() {
436     if (Android.isOnAndroidDevice()) {
437       // Old versions of Android had renamed the address field to 'effectiveDirectAddress', but
438       // recent versions of Android (>M?) use the OpenJDK implementation. Fall through in that case.
439       Field field = field(Buffer.class, "effectiveDirectAddress");
440       if (field != null) {
441         return field;
442       }
443     }
444     Field field = field(Buffer.class, "address");
445     return field != null && field.getType() == long.class ? field : null;
446   }
447 
448   /**
449    * Returns the index of the first byte where left and right differ, in the range [0, 8]. If {@code
450    * left == right}, the result will be 8, otherwise less than 8.
451    *
452    * <p>This counts from the *first* byte, which may be the most or least significant byte depending
453    * on the system endianness.
454    */
firstDifferingByteIndexNativeEndian(long left, long right)455   private static int firstDifferingByteIndexNativeEndian(long left, long right) {
456     int n =
457         IS_BIG_ENDIAN
458             ? Long.numberOfLeadingZeros(left ^ right)
459             : Long.numberOfTrailingZeros(left ^ right);
460     return n >> 3;
461   }
462 
463   /**
464    * Returns the lowest {@code index} such that {@code 0 <= index < length} and {@code left[leftOff
465    * + index] != right[rightOff + index]}. If no such value exists -- if {@code left} and {@code
466    * right} match up to {@code length} bytes from their respective offsets -- returns -1.
467    *
468    * <p>{@code leftOff + length} must be less than or equal to {@code left.length}, and the same for
469    * {@code right}.
470    */
mismatch(byte[] left, int leftOff, byte[] right, int rightOff, int length)471   static int mismatch(byte[] left, int leftOff, byte[] right, int rightOff, int length) {
472     if (leftOff < 0
473         || rightOff < 0
474         || length < 0
475         || leftOff + length > left.length
476         || rightOff + length > right.length) {
477       throw new IndexOutOfBoundsException();
478     }
479 
480     int index = 0;
481     if (HAS_UNSAFE_ARRAY_OPERATIONS) {
482       int leftAlignment = (BYTE_ARRAY_ALIGNMENT + leftOff) & STRIDE_ALIGNMENT_MASK;
483 
484       // Most CPUs handle getting chunks of bytes better on addresses that are a multiple of 4
485       // or 8.
486       // We walk one byte at a time until the left address, at least, is a multiple of 8.
487       // If the right address is, too, so much the better.
488       for (;
489           index < length && (leftAlignment & STRIDE_ALIGNMENT_MASK) != 0;
490           index++, leftAlignment++) {
491         if (left[leftOff + index] != right[rightOff + index]) {
492           return index;
493         }
494       }
495 
496       // Stride!  Grab eight bytes at a time from left and right and check them for equality.
497 
498       int strideLength = ((length - index) & ~STRIDE_ALIGNMENT_MASK) + index;
499       // strideLength is the point where we want to stop striding: it differs from index by
500       // a multiple of STRIDE, and it's the largest such number <= length.
501 
502       for (; index < strideLength; index += STRIDE) {
503         long leftLongWord = getLong(left, BYTE_ARRAY_BASE_OFFSET + leftOff + index);
504         long rightLongWord = getLong(right, BYTE_ARRAY_BASE_OFFSET + rightOff + index);
505         if (leftLongWord != rightLongWord) {
506           // one of these eight bytes differ!  use a helper to find out which one
507           return index + firstDifferingByteIndexNativeEndian(leftLongWord, rightLongWord);
508         }
509       }
510     }
511 
512     // If we were able to stride, there are at most STRIDE - 1 bytes left to compare.
513     // If we weren't, then this loop covers the whole thing.
514     for (; index < length; index++) {
515       if (left[leftOff + index] != right[rightOff + index]) {
516         return index;
517       }
518     }
519     return -1;
520   }
521 
522   /**
523    * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.Unsafe} is not
524    * available.
525    */
fieldOffset(Field field)526   private static long fieldOffset(Field field) {
527     return field == null || MEMORY_ACCESSOR == null ? -1 : MEMORY_ACCESSOR.objectFieldOffset(field);
528   }
529 
530   /**
531    * Gets the field with the given name within the class, or {@code null} if not found.
532    */
field(Class<?> clazz, String fieldName)533   private static Field field(Class<?> clazz, String fieldName) {
534     Field field;
535     try {
536       field = clazz.getDeclaredField(fieldName);
537     } catch (Throwable t) {
538       // Failed to access the fields.
539       field = null;
540     }
541     return field;
542   }
543 
544   private abstract static class MemoryAccessor {
545 
546     sun.misc.Unsafe unsafe;
547 
MemoryAccessor(sun.misc.Unsafe unsafe)548     MemoryAccessor(sun.misc.Unsafe unsafe) {
549       this.unsafe = unsafe;
550     }
551 
objectFieldOffset(Field field)552     public final long objectFieldOffset(Field field) {
553       return unsafe.objectFieldOffset(field);
554     }
555 
getByte(Object target, long offset)556     public abstract byte getByte(Object target, long offset);
557 
putByte(Object target, long offset, byte value)558     public abstract void putByte(Object target, long offset, byte value);
559 
getInt(Object target, long offset)560     public final int getInt(Object target, long offset) {
561       return unsafe.getInt(target, offset);
562     }
563 
putInt(Object target, long offset, int value)564     public final void putInt(Object target, long offset, int value) {
565       unsafe.putInt(target, offset, value);
566     }
567 
getLong(Object target, long offset)568     public final long getLong(Object target, long offset) {
569       return unsafe.getLong(target, offset);
570     }
571 
putLong(Object target, long offset, long value)572     public final void putLong(Object target, long offset, long value) {
573       unsafe.putLong(target, offset, value);
574     }
575 
getBoolean(Object target, long offset)576     public abstract boolean getBoolean(Object target, long offset);
577 
putBoolean(Object target, long offset, boolean value)578     public abstract void putBoolean(Object target, long offset, boolean value);
579 
getFloat(Object target, long offset)580     public abstract float getFloat(Object target, long offset);
581 
putFloat(Object target, long offset, float value)582     public abstract void putFloat(Object target, long offset, float value);
583 
getDouble(Object target, long offset)584     public abstract double getDouble(Object target, long offset);
585 
putDouble(Object target, long offset, double value)586     public abstract void putDouble(Object target, long offset, double value);
587 
getObject(Object target, long offset)588     public final Object getObject(Object target, long offset) {
589       return unsafe.getObject(target, offset);
590     }
591 
putObject(Object target, long offset, Object value)592     public final void putObject(Object target, long offset, Object value) {
593       unsafe.putObject(target, offset, value);
594     }
595 
arrayBaseOffset(Class<?> clazz)596     public final int arrayBaseOffset(Class<?> clazz) {
597       return unsafe.arrayBaseOffset(clazz);
598     }
599 
arrayIndexScale(Class<?> clazz)600     public final int arrayIndexScale(Class<?> clazz) {
601       return unsafe.arrayIndexScale(clazz);
602     }
603 
getByte(long address)604     public abstract byte getByte(long address);
605 
putByte(long address, byte value)606     public abstract void putByte(long address, byte value);
607 
getInt(long address)608     public abstract int getInt(long address);
609 
putInt(long address, int value)610     public abstract void putInt(long address, int value);
611 
getLong(long address)612     public abstract long getLong(long address);
613 
putLong(long address, long value)614     public abstract void putLong(long address, long value);
615 
getStaticObject(Field field)616     public abstract Object getStaticObject(Field field);
617 
copyMemory(long srcOffset, byte[] target, long targetIndex, long length)618     public abstract void copyMemory(long srcOffset, byte[] target, long targetIndex, long length);
619 
copyMemory(byte[] src, long srcIndex, long targetOffset, long length)620     public abstract void copyMemory(byte[] src, long srcIndex, long targetOffset, long length);
621   }
622 
623   private static final class JvmMemoryAccessor extends MemoryAccessor {
624 
JvmMemoryAccessor(sun.misc.Unsafe unsafe)625     JvmMemoryAccessor(sun.misc.Unsafe unsafe) {
626       super(unsafe);
627     }
628 
629     @Override
getByte(long address)630     public byte getByte(long address) {
631       return unsafe.getByte(address);
632     }
633 
634     @Override
putByte(long address, byte value)635     public void putByte(long address, byte value) {
636       unsafe.putByte(address, value);
637     }
638 
639     @Override
getInt(long address)640     public int getInt(long address) {
641       return unsafe.getInt(address);
642     }
643 
644     @Override
putInt(long address, int value)645     public void putInt(long address, int value) {
646       unsafe.putInt(address, value);
647     }
648 
649     @Override
getLong(long address)650     public long getLong(long address) {
651       return unsafe.getLong(address);
652     }
653 
654     @Override
putLong(long address, long value)655     public void putLong(long address, long value) {
656       unsafe.putLong(address, value);
657     }
658 
659     @Override
getByte(Object target, long offset)660     public byte getByte(Object target, long offset) {
661       return unsafe.getByte(target, offset);
662     }
663 
664     @Override
putByte(Object target, long offset, byte value)665     public void putByte(Object target, long offset, byte value) {
666       unsafe.putByte(target, offset, value);
667     }
668 
669     @Override
getBoolean(Object target, long offset)670     public boolean getBoolean(Object target, long offset) {
671       return unsafe.getBoolean(target, offset);
672     }
673 
674     @Override
putBoolean(Object target, long offset, boolean value)675     public void putBoolean(Object target, long offset, boolean value) {
676       unsafe.putBoolean(target, offset, value);
677     }
678 
679     @Override
getFloat(Object target, long offset)680     public float getFloat(Object target, long offset) {
681       return unsafe.getFloat(target, offset);
682     }
683 
684     @Override
putFloat(Object target, long offset, float value)685     public void putFloat(Object target, long offset, float value) {
686       unsafe.putFloat(target, offset, value);
687     }
688 
689     @Override
getDouble(Object target, long offset)690     public double getDouble(Object target, long offset) {
691       return unsafe.getDouble(target, offset);
692     }
693 
694     @Override
putDouble(Object target, long offset, double value)695     public void putDouble(Object target, long offset, double value) {
696       unsafe.putDouble(target, offset, value);
697     }
698 
699     @Override
copyMemory(long srcOffset, byte[] target, long targetIndex, long length)700     public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
701       unsafe.copyMemory(null, srcOffset, target, BYTE_ARRAY_BASE_OFFSET + targetIndex, length);
702     }
703 
704     @Override
copyMemory(byte[] src, long srcIndex, long targetOffset, long length)705     public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
706       unsafe.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, targetOffset, length);
707     }
708 
709     @Override
getStaticObject(Field field)710     public Object getStaticObject(Field field) {
711       return getObject(unsafe.staticFieldBase(field), unsafe.staticFieldOffset(field));
712     }
713   }
714 
715   private static final class Android64MemoryAccessor extends MemoryAccessor {
716 
Android64MemoryAccessor(sun.misc.Unsafe unsafe)717     Android64MemoryAccessor(sun.misc.Unsafe unsafe) {
718       super(unsafe);
719     }
720 
721     @Override
getByte(long address)722     public byte getByte(long address) {
723       throw new UnsupportedOperationException();
724     }
725 
726     @Override
putByte(long address, byte value)727     public void putByte(long address, byte value) {
728       throw new UnsupportedOperationException();
729     }
730 
731     @Override
getInt(long address)732     public int getInt(long address) {
733       throw new UnsupportedOperationException();
734     }
735 
736     @Override
putInt(long address, int value)737     public void putInt(long address, int value) {
738       throw new UnsupportedOperationException();
739     }
740 
741     @Override
getLong(long address)742     public long getLong(long address) {
743       throw new UnsupportedOperationException();
744     }
745 
746     @Override
putLong(long address, long value)747     public void putLong(long address, long value) {
748       throw new UnsupportedOperationException();
749     }
750 
751     @Override
getByte(Object target, long offset)752     public byte getByte(Object target, long offset) {
753       if (IS_BIG_ENDIAN) {
754         return getByteBigEndian(target, offset);
755       } else {
756         return getByteLittleEndian(target, offset);
757       }
758     }
759 
760     @Override
putByte(Object target, long offset, byte value)761     public void putByte(Object target, long offset, byte value) {
762       if (IS_BIG_ENDIAN) {
763         putByteBigEndian(target, offset, value);
764       } else {
765         putByteLittleEndian(target, offset, value);
766       }
767     }
768 
769     @Override
getBoolean(Object target, long offset)770     public boolean getBoolean(Object target, long offset) {
771       if (IS_BIG_ENDIAN) {
772         return getBooleanBigEndian(target, offset);
773       } else {
774         return getBooleanLittleEndian(target, offset);
775       }
776     }
777 
778     @Override
putBoolean(Object target, long offset, boolean value)779     public void putBoolean(Object target, long offset, boolean value) {
780       if (IS_BIG_ENDIAN) {
781         putBooleanBigEndian(target, offset, value);
782       } else {
783         putBooleanLittleEndian(target, offset, value);
784       }
785     }
786 
787     @Override
getFloat(Object target, long offset)788     public float getFloat(Object target, long offset) {
789       return Float.intBitsToFloat(getInt(target, offset));
790     }
791 
792     @Override
putFloat(Object target, long offset, float value)793     public void putFloat(Object target, long offset, float value) {
794       putInt(target, offset, Float.floatToIntBits(value));
795     }
796 
797     @Override
getDouble(Object target, long offset)798     public double getDouble(Object target, long offset) {
799       return Double.longBitsToDouble(getLong(target, offset));
800     }
801 
802     @Override
putDouble(Object target, long offset, double value)803     public void putDouble(Object target, long offset, double value) {
804       putLong(target, offset, Double.doubleToLongBits(value));
805     }
806 
807     @Override
copyMemory(long srcOffset, byte[] target, long targetIndex, long length)808     public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
809       throw new UnsupportedOperationException();
810     }
811 
812     @Override
copyMemory(byte[] src, long srcIndex, long targetOffset, long length)813     public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
814       throw new UnsupportedOperationException();
815     }
816 
817     @Override
getStaticObject(Field field)818     public Object getStaticObject(Field field) {
819       try {
820         return field.get(null);
821       } catch (IllegalAccessException e) {
822         return null;
823       }
824     }
825   }
826 
827   private static final class Android32MemoryAccessor extends MemoryAccessor {
828 
829     /** Mask used to convert a 64 bit memory address to a 32 bit address. */
830     private static final long SMALL_ADDRESS_MASK = 0x00000000FFFFFFFF;
831 
832     /** Truncate a {@code long} address into a short {@code int} address. */
smallAddress(long address)833     private static int smallAddress(long address) {
834       return (int) (SMALL_ADDRESS_MASK & address);
835     }
836 
Android32MemoryAccessor(sun.misc.Unsafe unsafe)837     Android32MemoryAccessor(sun.misc.Unsafe unsafe) {
838       super(unsafe);
839     }
840 
841     @Override
getByte(long address)842     public byte getByte(long address) {
843       throw new UnsupportedOperationException();
844     }
845 
846     @Override
putByte(long address, byte value)847     public void putByte(long address, byte value) {
848       throw new UnsupportedOperationException();
849     }
850 
851     @Override
getInt(long address)852     public int getInt(long address) {
853       throw new UnsupportedOperationException();
854     }
855 
856     @Override
putInt(long address, int value)857     public void putInt(long address, int value) {
858       throw new UnsupportedOperationException();
859     }
860 
861     @Override
getLong(long address)862     public long getLong(long address) {
863       throw new UnsupportedOperationException();
864     }
865 
866     @Override
putLong(long address, long value)867     public void putLong(long address, long value) {
868       throw new UnsupportedOperationException();
869     }
870 
871     @Override
getByte(Object target, long offset)872     public byte getByte(Object target, long offset) {
873       if (IS_BIG_ENDIAN) {
874         return getByteBigEndian(target, offset);
875       } else {
876         return getByteLittleEndian(target, offset);
877       }
878     }
879 
880     @Override
putByte(Object target, long offset, byte value)881     public void putByte(Object target, long offset, byte value) {
882       if (IS_BIG_ENDIAN) {
883         putByteBigEndian(target, offset, value);
884       } else {
885         putByteLittleEndian(target, offset, value);
886       }
887     }
888 
889     @Override
getBoolean(Object target, long offset)890     public boolean getBoolean(Object target, long offset) {
891       if (IS_BIG_ENDIAN) {
892         return getBooleanBigEndian(target, offset);
893       } else {
894         return getBooleanLittleEndian(target, offset);
895       }
896     }
897 
898     @Override
putBoolean(Object target, long offset, boolean value)899     public void putBoolean(Object target, long offset, boolean value) {
900       if (IS_BIG_ENDIAN) {
901         putBooleanBigEndian(target, offset, value);
902       } else {
903         putBooleanLittleEndian(target, offset, value);
904       }
905     }
906 
907     @Override
getFloat(Object target, long offset)908     public float getFloat(Object target, long offset) {
909       return Float.intBitsToFloat(getInt(target, offset));
910     }
911 
912     @Override
putFloat(Object target, long offset, float value)913     public void putFloat(Object target, long offset, float value) {
914       putInt(target, offset, Float.floatToIntBits(value));
915     }
916 
917     @Override
getDouble(Object target, long offset)918     public double getDouble(Object target, long offset) {
919       return Double.longBitsToDouble(getLong(target, offset));
920     }
921 
922     @Override
putDouble(Object target, long offset, double value)923     public void putDouble(Object target, long offset, double value) {
924       putLong(target, offset, Double.doubleToLongBits(value));
925     }
926 
927     @Override
copyMemory(long srcOffset, byte[] target, long targetIndex, long length)928     public void copyMemory(long srcOffset, byte[] target, long targetIndex, long length) {
929       throw new UnsupportedOperationException();
930     }
931 
932     @Override
copyMemory(byte[] src, long srcIndex, long targetOffset, long length)933     public void copyMemory(byte[] src, long srcIndex, long targetOffset, long length) {
934       throw new UnsupportedOperationException();
935     }
936 
937     @Override
getStaticObject(Field field)938     public Object getStaticObject(Field field) {
939       try {
940         return field.get(null);
941       } catch (IllegalAccessException e) {
942         return null;
943       }
944     }
945   }
946 
getByteBigEndian(Object target, long offset)947   private static byte getByteBigEndian(Object target, long offset) {
948     return (byte) ((getInt(target, offset & ~3) >>> ((~offset & 3) << 3)) & 0xFF);
949   }
950 
getByteLittleEndian(Object target, long offset)951   private static byte getByteLittleEndian(Object target, long offset) {
952     return (byte) ((getInt(target, offset & ~3) >>> ((offset & 3) << 3)) & 0xFF);
953   }
954 
putByteBigEndian(Object target, long offset, byte value)955   private static void putByteBigEndian(Object target, long offset, byte value) {
956     int intValue = getInt(target, offset & ~3);
957     int shift = ((~(int) offset) & 3) << 3;
958     int output = (intValue & ~(0xFF << shift)) | ((0xFF & value) << shift);
959     putInt(target, offset & ~3, output);
960   }
961 
putByteLittleEndian(Object target, long offset, byte value)962   private static void putByteLittleEndian(Object target, long offset, byte value) {
963     int intValue = getInt(target, offset & ~3);
964     int shift = (((int) offset) & 3) << 3;
965     int output = (intValue & ~(0xFF << shift)) | ((0xFF & value) << shift);
966     putInt(target, offset & ~3, output);
967   }
968 
getBooleanBigEndian(Object target, long offset)969   private static boolean getBooleanBigEndian(Object target, long offset) {
970     return getByteBigEndian(target, offset) != 0;
971   }
972 
getBooleanLittleEndian(Object target, long offset)973   private static boolean getBooleanLittleEndian(Object target, long offset) {
974     return getByteLittleEndian(target, offset) != 0;
975   }
976 
putBooleanBigEndian(Object target, long offset, boolean value)977   private static void putBooleanBigEndian(Object target, long offset, boolean value) {
978     putByteBigEndian(target, offset, (byte) (value ? 1 : 0));
979   }
980 
putBooleanLittleEndian(Object target, long offset, boolean value)981   private static void putBooleanLittleEndian(Object target, long offset, boolean value) {
982     putByteLittleEndian(target, offset, (byte) (value ? 1 : 0));
983   }
984 }
985