| OLD | NEW |
| (Empty) |
| 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.security.AccessController; | |
| 37 import java.security.PrivilegedExceptionAction; | |
| 38 import sun.misc.Unsafe; | |
| 39 | |
| 40 /** Utility class for working with unsafe operations. */ | |
| 41 // TODO(nathanmittler): Add support for Android Memory/MemoryBlock | |
| 42 final class UnsafeUtil { | |
| 43 private static final sun.misc.Unsafe UNSAFE = getUnsafe(); | |
| 44 private static final boolean HAS_UNSAFE_BYTEBUFFER_OPERATIONS = | |
| 45 supportsUnsafeByteBufferOperations(); | |
| 46 private static final boolean HAS_UNSAFE_ARRAY_OPERATIONS = supportsUnsafeArray
Operations(); | |
| 47 private static final long ARRAY_BASE_OFFSET = byteArrayBaseOffset(); | |
| 48 private static final long BUFFER_ADDRESS_OFFSET = fieldOffset(field(Buffer.cla
ss, "address")); | |
| 49 | |
| 50 private UnsafeUtil() {} | |
| 51 | |
| 52 static boolean hasUnsafeArrayOperations() { | |
| 53 return HAS_UNSAFE_ARRAY_OPERATIONS; | |
| 54 } | |
| 55 | |
| 56 static boolean hasUnsafeByteBufferOperations() { | |
| 57 return HAS_UNSAFE_BYTEBUFFER_OPERATIONS; | |
| 58 } | |
| 59 | |
| 60 static Object allocateInstance(Class<?> clazz) { | |
| 61 try { | |
| 62 return UNSAFE.allocateInstance(clazz); | |
| 63 } catch (InstantiationException e) { | |
| 64 throw new RuntimeException(e); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 static long objectFieldOffset(Field field) { | |
| 69 return UNSAFE.objectFieldOffset(field); | |
| 70 } | |
| 71 | |
| 72 static long getArrayBaseOffset() { | |
| 73 return ARRAY_BASE_OFFSET; | |
| 74 } | |
| 75 | |
| 76 static byte getByte(Object target, long offset) { | |
| 77 return UNSAFE.getByte(target, offset); | |
| 78 } | |
| 79 | |
| 80 static void putByte(Object target, long offset, byte value) { | |
| 81 UNSAFE.putByte(target, offset, value); | |
| 82 } | |
| 83 | |
| 84 static int getInt(Object target, long offset) { | |
| 85 return UNSAFE.getInt(target, offset); | |
| 86 } | |
| 87 | |
| 88 static void putInt(Object target, long offset, int value) { | |
| 89 UNSAFE.putInt(target, offset, value); | |
| 90 } | |
| 91 | |
| 92 static long getLong(Object target, long offset) { | |
| 93 return UNSAFE.getLong(target, offset); | |
| 94 } | |
| 95 | |
| 96 static void putLong(Object target, long offset, long value) { | |
| 97 UNSAFE.putLong(target, offset, value); | |
| 98 } | |
| 99 | |
| 100 static boolean getBoolean(Object target, long offset) { | |
| 101 return UNSAFE.getBoolean(target, offset); | |
| 102 } | |
| 103 | |
| 104 static void putBoolean(Object target, long offset, boolean value) { | |
| 105 UNSAFE.putBoolean(target, offset, value); | |
| 106 } | |
| 107 | |
| 108 static float getFloat(Object target, long offset) { | |
| 109 return UNSAFE.getFloat(target, offset); | |
| 110 } | |
| 111 | |
| 112 static void putFloat(Object target, long offset, float value) { | |
| 113 UNSAFE.putFloat(target, offset, value); | |
| 114 } | |
| 115 | |
| 116 static double getDouble(Object target, long offset) { | |
| 117 return UNSAFE.getDouble(target, offset); | |
| 118 } | |
| 119 | |
| 120 static void putDouble(Object target, long offset, double value) { | |
| 121 UNSAFE.putDouble(target, offset, value); | |
| 122 } | |
| 123 | |
| 124 static Object getObject(Object target, long offset) { | |
| 125 return UNSAFE.getObject(target, offset); | |
| 126 } | |
| 127 | |
| 128 static void putObject(Object target, long offset, Object value) { | |
| 129 UNSAFE.putObject(target, offset, value); | |
| 130 } | |
| 131 | |
| 132 static void copyMemory( | |
| 133 Object src, long srcOffset, Object target, long targetOffset, long length)
{ | |
| 134 UNSAFE.copyMemory(src, srcOffset, target, targetOffset, length); | |
| 135 } | |
| 136 | |
| 137 static byte getByte(long address) { | |
| 138 return UNSAFE.getByte(address); | |
| 139 } | |
| 140 | |
| 141 static void putByte(long address, byte value) { | |
| 142 UNSAFE.putByte(address, value); | |
| 143 } | |
| 144 | |
| 145 static int getInt(long address) { | |
| 146 return UNSAFE.getInt(address); | |
| 147 } | |
| 148 | |
| 149 static void putInt(long address, int value) { | |
| 150 UNSAFE.putInt(address, value); | |
| 151 } | |
| 152 | |
| 153 static long getLong(long address) { | |
| 154 return UNSAFE.getLong(address); | |
| 155 } | |
| 156 | |
| 157 static void putLong(long address, long value) { | |
| 158 UNSAFE.putLong(address, value); | |
| 159 } | |
| 160 | |
| 161 static void copyMemory(long srcAddress, long targetAddress, long length) { | |
| 162 UNSAFE.copyMemory(srcAddress, targetAddress, length); | |
| 163 } | |
| 164 | |
| 165 static void setMemory(long address, long numBytes, byte value) { | |
| 166 UNSAFE.setMemory(address, numBytes, value); | |
| 167 } | |
| 168 | |
| 169 /** | |
| 170 * Gets the offset of the {@code address} field of the given direct {@link Byt
eBuffer}. | |
| 171 */ | |
| 172 static long addressOffset(ByteBuffer buffer) { | |
| 173 return UNSAFE.getLong(buffer, BUFFER_ADDRESS_OFFSET); | |
| 174 } | |
| 175 | |
| 176 /** | |
| 177 * Gets the {@code sun.misc.Unsafe} instance, or {@code null} if not available
on this platform. | |
| 178 */ | |
| 179 private static sun.misc.Unsafe getUnsafe() { | |
| 180 sun.misc.Unsafe unsafe = null; | |
| 181 try { | |
| 182 unsafe = | |
| 183 AccessController.doPrivileged( | |
| 184 new PrivilegedExceptionAction<Unsafe>() { | |
| 185 @Override | |
| 186 public sun.misc.Unsafe run() throws Exception { | |
| 187 Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class; | |
| 188 | |
| 189 for (Field f : k.getDeclaredFields()) { | |
| 190 f.setAccessible(true); | |
| 191 Object x = f.get(null); | |
| 192 if (k.isInstance(x)) { | |
| 193 return k.cast(x); | |
| 194 } | |
| 195 } | |
| 196 // The sun.misc.Unsafe field does not exist. | |
| 197 return null; | |
| 198 } | |
| 199 }); | |
| 200 } catch (Throwable e) { | |
| 201 // Catching Throwable here due to the fact that Google AppEngine raises No
ClassDefFoundError | |
| 202 // for Unsafe. | |
| 203 } | |
| 204 return unsafe; | |
| 205 } | |
| 206 | |
| 207 /** Indicates whether or not unsafe array operations are supported on this pla
tform. */ | |
| 208 private static boolean supportsUnsafeArrayOperations() { | |
| 209 boolean supported = false; | |
| 210 if (UNSAFE != null) { | |
| 211 try { | |
| 212 Class<?> clazz = UNSAFE.getClass(); | |
| 213 clazz.getMethod("objectFieldOffset", Field.class); | |
| 214 clazz.getMethod("allocateInstance", Class.class); | |
| 215 clazz.getMethod("arrayBaseOffset", Class.class); | |
| 216 clazz.getMethod("getByte", Object.class, long.class); | |
| 217 clazz.getMethod("putByte", Object.class, long.class, byte.class); | |
| 218 clazz.getMethod("getBoolean", Object.class, long.class); | |
| 219 clazz.getMethod("putBoolean", Object.class, long.class, boolean.class); | |
| 220 clazz.getMethod("getInt", Object.class, long.class); | |
| 221 clazz.getMethod("putInt", Object.class, long.class, int.class); | |
| 222 clazz.getMethod("getLong", Object.class, long.class); | |
| 223 clazz.getMethod("putLong", Object.class, long.class, long.class); | |
| 224 clazz.getMethod("getFloat", Object.class, long.class); | |
| 225 clazz.getMethod("putFloat", Object.class, long.class, float.class); | |
| 226 clazz.getMethod("getDouble", Object.class, long.class); | |
| 227 clazz.getMethod("putDouble", Object.class, long.class, double.class); | |
| 228 clazz.getMethod("getObject", Object.class, long.class); | |
| 229 clazz.getMethod("putObject", Object.class, long.class, Object.class); | |
| 230 clazz.getMethod( | |
| 231 "copyMemory", Object.class, long.class, Object.class, long.class, lo
ng.class); | |
| 232 supported = true; | |
| 233 } catch (Throwable e) { | |
| 234 // Do nothing. | |
| 235 } | |
| 236 } | |
| 237 return supported; | |
| 238 } | |
| 239 | |
| 240 private static boolean supportsUnsafeByteBufferOperations() { | |
| 241 boolean supported = false; | |
| 242 if (UNSAFE != null) { | |
| 243 try { | |
| 244 Class<?> clazz = UNSAFE.getClass(); | |
| 245 // Methods for getting direct buffer address. | |
| 246 clazz.getMethod("objectFieldOffset", Field.class); | |
| 247 clazz.getMethod("getLong", Object.class, long.class); | |
| 248 | |
| 249 clazz.getMethod("getByte", long.class); | |
| 250 clazz.getMethod("putByte", long.class, byte.class); | |
| 251 clazz.getMethod("getInt", long.class); | |
| 252 clazz.getMethod("putInt", long.class, int.class); | |
| 253 clazz.getMethod("getLong", long.class); | |
| 254 clazz.getMethod("putLong", long.class, long.class); | |
| 255 clazz.getMethod("setMemory", long.class, long.class, byte.class); | |
| 256 clazz.getMethod("copyMemory", long.class, long.class, long.class); | |
| 257 supported = true; | |
| 258 } catch (Throwable e) { | |
| 259 // Do nothing. | |
| 260 } | |
| 261 } | |
| 262 return supported; | |
| 263 } | |
| 264 | |
| 265 /** | |
| 266 * Get the base offset for byte arrays, or {@code -1} if {@code sun.misc.Unsaf
e} is not available. | |
| 267 */ | |
| 268 private static int byteArrayBaseOffset() { | |
| 269 return HAS_UNSAFE_ARRAY_OPERATIONS ? UNSAFE.arrayBaseOffset(byte[].class) :
-1; | |
| 270 } | |
| 271 | |
| 272 /** | |
| 273 * Returns the offset of the provided field, or {@code -1} if {@code sun.misc.
Unsafe} is not | |
| 274 * available. | |
| 275 */ | |
| 276 private static long fieldOffset(Field field) { | |
| 277 return field == null || UNSAFE == null ? -1 : UNSAFE.objectFieldOffset(field
); | |
| 278 } | |
| 279 | |
| 280 /** | |
| 281 * Gets the field with the given name within the class, or {@code null} if not
found. If found, | |
| 282 * the field is made accessible. | |
| 283 */ | |
| 284 private static Field field(Class<?> clazz, String fieldName) { | |
| 285 Field field; | |
| 286 try { | |
| 287 field = clazz.getDeclaredField(fieldName); | |
| 288 field.setAccessible(true); | |
| 289 } catch (Throwable t) { | |
| 290 // Failed to access the fields. | |
| 291 field = null; | |
| 292 } | |
| 293 return field; | |
| 294 } | |
| 295 } | |
| OLD | NEW |