31 package com.google.protobuf;
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;
43 final class UnsafeUtil {
44 private static final Logger logger = Logger.getLogger(UnsafeUtil.class.getName());
45 private static final sun.misc.Unsafe UNSAFE = getUnsafe();
46 private static final MemoryAccessor MEMORY_ACCESSOR = getMemoryAccessor();
47 private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS =
48 supportsUnsafeByteBufferOperations();
49 private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArrayOperations();
51 static final long BYTE_ARRAY_BASE_OFFSET = arrayBaseOffset(
byte[].
class);
55 private static final long BOOLEAN_ARRAY_BASE_OFFSET = arrayBaseOffset(
boolean[].
class);
56 private static final long BOOLEAN_ARRAY_INDEX_SCALE = arrayIndexScale(
boolean[].
class);
58 private static final long INT_ARRAY_BASE_OFFSET = arrayBaseOffset(
int[].
class);
59 private static final long INT_ARRAY_INDEX_SCALE = arrayIndexScale(
int[].
class);
61 private static final long LONG_ARRAY_BASE_OFFSET = arrayBaseOffset(
long[].
class);
62 private static final long LONG_ARRAY_INDEX_SCALE = arrayIndexScale(
long[].
class);
64 private static final long FLOAT_ARRAY_BASE_OFFSET = arrayBaseOffset(
float[].
class);
65 private static final long FLOAT_ARRAY_INDEX_SCALE = arrayIndexScale(
float[].
class);
67 private static final long DOUBLE_ARRAY_BASE_OFFSET = arrayBaseOffset(
double[].
class);
68 private static final long DOUBLE_ARRAY_INDEX_SCALE = arrayIndexScale(
double[].
class);
70 private static final long OBJECT_ARRAY_BASE_OFFSET = arrayBaseOffset(Object[].
class);
71 private static final long OBJECT_ARRAY_INDEX_SCALE = arrayIndexScale(Object[].
class);
73 private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(bufferAddressField());
75 private static final int STRIDE = 8;
76 private static final int STRIDE_ALIGNMENT_MASK = STRIDE - 1;
77 private static final int BYTE_ARRAY_ALIGNMENT =
78 (int) (BYTE_ARRAY_BASE_OFFSET & STRIDE_ALIGNMENT_MASK);
80 static final boolean IS_BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
82 private UnsafeUtil() {}
84 static boolean hasUnsafeArrayOperations() {
85 return HAS_UNSAFE_ARRAY_OPERATIONS;
88 static boolean hasUnsafeByteBufferOperations() {
89 return HAS_UNSAFE_BYTEBUFFER_OPERATIONS;
93 @SuppressWarnings(
"unchecked")
94 static <
T>
T allocateInstance(Class<
T> clazz) {
96 return (
T) UNSAFE.allocateInstance(clazz);
97 }
catch (InstantiationException e) {
98 throw new IllegalStateException(e);
103 return MEMORY_ACCESSOR.objectFieldOffset(
field);
106 private static int arrayBaseOffset(Class<?> clazz) {
107 return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayBaseOffset(clazz) : -1;
110 private static int arrayIndexScale(Class<?> clazz) {
111 return HAS_UNSAFE_ARRAY_OPERATIONS ? MEMORY_ACCESSOR.arrayIndexScale(clazz) : -1;
171 return MEMORY_ACCESSOR.getByte(
target, BYTE_ARRAY_BASE_OFFSET +
index);
179 return MEMORY_ACCESSOR.getInt(
target, INT_ARRAY_BASE_OFFSET + (
index * INT_ARRAY_INDEX_SCALE));
183 MEMORY_ACCESSOR.putInt(
target, INT_ARRAY_BASE_OFFSET + (
index * INT_ARRAY_INDEX_SCALE),
value);
187 return MEMORY_ACCESSOR.getLong(
188 target, LONG_ARRAY_BASE_OFFSET + (
index * LONG_ARRAY_INDEX_SCALE));
192 MEMORY_ACCESSOR.putLong(
196 static boolean getBoolean(
boolean[]
target,
long index) {
197 return MEMORY_ACCESSOR.getBoolean(
198 target, BOOLEAN_ARRAY_BASE_OFFSET + (
index * BOOLEAN_ARRAY_INDEX_SCALE));
202 MEMORY_ACCESSOR.putBoolean(
203 target, BOOLEAN_ARRAY_BASE_OFFSET + (
index * BOOLEAN_ARRAY_INDEX_SCALE),
value);
206 static float getFloat(
float[]
target,
long index) {
207 return MEMORY_ACCESSOR.getFloat(
208 target, FLOAT_ARRAY_BASE_OFFSET + (
index * FLOAT_ARRAY_INDEX_SCALE));
212 MEMORY_ACCESSOR.putFloat(
213 target, FLOAT_ARRAY_BASE_OFFSET + (
index * FLOAT_ARRAY_INDEX_SCALE),
value);
216 static double getDouble(
double[]
target,
long index) {
217 return MEMORY_ACCESSOR.getDouble(
218 target, DOUBLE_ARRAY_BASE_OFFSET + (
index * DOUBLE_ARRAY_INDEX_SCALE));
222 MEMORY_ACCESSOR.putDouble(
223 target, DOUBLE_ARRAY_BASE_OFFSET + (
index * DOUBLE_ARRAY_INDEX_SCALE),
value);
226 static Object getObject(Object[]
target,
long index) {
227 return MEMORY_ACCESSOR.getObject(
228 target, OBJECT_ARRAY_BASE_OFFSET + (
index * OBJECT_ARRAY_INDEX_SCALE));
232 MEMORY_ACCESSOR.putObject(
233 target, OBJECT_ARRAY_BASE_OFFSET + (
index * OBJECT_ARRAY_INDEX_SCALE),
value);
236 static void copyMemory(
byte[]
src,
long srcIndex,
long targetOffset,
long length) {
237 MEMORY_ACCESSOR.copyMemory(
src, srcIndex, targetOffset,
length);
240 static void copyMemory(
long srcOffset,
byte[]
target,
long targetIndex,
long length) {
241 MEMORY_ACCESSOR.copyMemory(srcOffset,
target, targetIndex,
length);
244 static void copyMemory(
byte[]
src,
long srcIndex,
byte[]
target,
long targetIndex,
long length) {
245 System.arraycopy(
src, (
int) srcIndex,
target, (
int) targetIndex, (
int)
length);
248 static byte getByte(
long address) {
249 return MEMORY_ACCESSOR.getByte(
address);
256 static int getInt(
long address) {
257 return MEMORY_ACCESSOR.getInt(
address);
264 static long getLong(
long address) {
265 return MEMORY_ACCESSOR.getLong(
address);
273 static long addressOffset(ByteBuffer
buffer) {
274 return MEMORY_ACCESSOR.getLong(
buffer, BUFFER_ADDRESS_OFFSET);
278 return MEMORY_ACCESSOR.getStaticObject(
field);
284 static sun.misc.Unsafe getUnsafe() {
285 sun.misc.Unsafe unsafe =
null;
288 AccessController.doPrivileged(
289 new PrivilegedExceptionAction<sun.misc.Unsafe>() {
291 public sun.misc.Unsafe run() throws Exception {
292 Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
294 for (
Field f : k.getDeclaredFields()) {
295 f.setAccessible(
true);
296 Object
x =
f.get(
null);
297 if (k.isInstance(
x)) {
305 }
catch (Throwable e) {
313 private static MemoryAccessor getMemoryAccessor() {
314 if (UNSAFE ==
null) {
317 return new JvmMemoryAccessor(UNSAFE);
321 private static boolean supportsUnsafeArrayOperations() {
322 if (UNSAFE ==
null) {
326 Class<?> clazz = UNSAFE.getClass();
327 clazz.getMethod(
"objectFieldOffset",
Field.class);
328 clazz.getMethod(
"arrayBaseOffset", Class.class);
329 clazz.getMethod(
"arrayIndexScale", Class.class);
330 clazz.getMethod(
"getInt", Object.class,
long.class);
331 clazz.getMethod(
"putInt", Object.class,
long.class,
int.class);
332 clazz.getMethod(
"getLong", Object.class,
long.class);
333 clazz.getMethod(
"putLong", Object.class,
long.class,
long.class);
334 clazz.getMethod(
"getObject", Object.class,
long.class);
335 clazz.getMethod(
"putObject", Object.class,
long.class, Object.class);
336 clazz.getMethod(
"getByte", Object.class,
long.class);
337 clazz.getMethod(
"putByte", Object.class,
long.class,
byte.class);
338 clazz.getMethod(
"getBoolean", Object.class,
long.class);
339 clazz.getMethod(
"putBoolean", Object.class,
long.class,
boolean.class);
340 clazz.getMethod(
"getFloat", Object.class,
long.class);
341 clazz.getMethod(
"putFloat", Object.class,
long.class,
float.class);
342 clazz.getMethod(
"getDouble", Object.class,
long.class);
343 clazz.getMethod(
"putDouble", Object.class,
long.class,
double.class);
346 }
catch (Throwable e) {
349 "platform method missing - proto runtime falling back to safer methods: " + e);
354 private static boolean supportsUnsafeByteBufferOperations() {
355 if (UNSAFE ==
null) {
359 Class<?> clazz = UNSAFE.getClass();
361 clazz.getMethod(
"objectFieldOffset",
Field.class);
362 clazz.getMethod(
"getLong", Object.class,
long.class);
364 if (bufferAddressField() ==
null) {
368 clazz.getMethod(
"getByte",
long.
class);
369 clazz.getMethod(
"putByte",
long.
class,
byte.
class);
370 clazz.getMethod(
"getInt",
long.
class);
371 clazz.getMethod(
"putInt",
long.
class,
int.
class);
372 clazz.getMethod(
"getLong",
long.
class);
373 clazz.getMethod(
"putLong",
long.
class,
long.
class);
374 clazz.getMethod(
"copyMemory",
long.
class,
long.
class,
long.
class);
375 clazz.getMethod(
"copyMemory", Object.class,
long.class, Object.class,
long.class,
long.class);
377 }
catch (Throwable e) {
380 "platform method missing - proto runtime falling back to safer methods: " + e);
387 private static Field bufferAddressField() {
399 private static int firstDifferingByteIndexNativeEndian(
long left,
long right) {
402 ? Long.numberOfLeadingZeros(
left ^ right)
403 : Long.numberOfTrailingZeros(
left ^ right);
415 static int mismatch(
byte[]
left,
int leftOff,
byte[] right,
int rightOff,
int length) {
420 || rightOff +
length > right.length) {
421 throw new IndexOutOfBoundsException();
425 if (HAS_UNSAFE_ARRAY_OPERATIONS) {
426 int leftAlignment = (BYTE_ARRAY_ALIGNMENT + leftOff) & STRIDE_ALIGNMENT_MASK;
433 index <
length && (leftAlignment & STRIDE_ALIGNMENT_MASK) != 0;
434 index++, leftAlignment++) {
446 for (;
index < strideLength;
index += STRIDE) {
447 long leftLongWord = getLong(
left, BYTE_ARRAY_BASE_OFFSET + leftOff +
index);
448 long rightLongWord = getLong(right, BYTE_ARRAY_BASE_OFFSET + rightOff +
index);
449 if (leftLongWord != rightLongWord) {
451 return index + firstDifferingByteIndexNativeEndian(leftLongWord, rightLongWord);
470 private static long fieldOffset(
Field field) {
471 return field ==
null || MEMORY_ACCESSOR ==
null ? -1 : MEMORY_ACCESSOR.objectFieldOffset(
field);
477 private static Field field(Class<?> clazz, String fieldName) {
480 field = clazz.getDeclaredField(fieldName);
481 }
catch (Throwable t) {
490 sun.misc.Unsafe unsafe;
493 this.unsafe = unsafe;
497 return unsafe.objectFieldOffset(
field);
541 return unsafe.arrayBaseOffset(clazz);
545 return unsafe.arrayIndexScale(clazz);
564 public abstract void copyMemory(
byte[]
src,
long srcIndex,
long targetOffset,
long length);
575 return unsafe.getByte(
address);
595 return unsafe.getLong(
address);
645 unsafe.copyMemory(
null, srcOffset,
target, BYTE_ARRAY_BASE_OFFSET + targetIndex,
length);
650 unsafe.copyMemory(
src, BYTE_ARRAY_BASE_OFFSET + srcIndex,
null, targetOffset,
length);