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 |