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 |