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