View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.util.internal;
17  
18  import io.netty.util.internal.logging.InternalLogger;
19  import io.netty.util.internal.logging.InternalLoggerFactory;
20  import sun.misc.Unsafe;
21  
22  import java.lang.reflect.Field;
23  import java.lang.reflect.Method;
24  import java.nio.Buffer;
25  import java.nio.ByteBuffer;
26  import java.nio.ByteOrder;
27  import java.security.AccessController;
28  import java.security.PrivilegedAction;
29  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
30  import java.util.concurrent.atomic.AtomicLongFieldUpdater;
31  import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
32  
33  /**
34   * The {@link PlatformDependent} operations which requires access to {@code sun.misc.*}.
35   */
36  final class PlatformDependent0 {
37  
38      private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
39      private static final Unsafe UNSAFE;
40      private static final boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
41      private static final long ADDRESS_FIELD_OFFSET;
42  
43      /**
44       * Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow safepoint polling
45       * during a large copy.
46       */
47      private static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
48  
49      /**
50       * {@code true} if and only if the platform supports unaligned access.
51       *
52       * @see <a href="http://en.wikipedia.org/wiki/Segmentation_fault#Bus_error">Wikipedia on segfault</a>
53       */
54      private static final boolean UNALIGNED;
55  
56      static {
57          ByteBuffer direct = ByteBuffer.allocateDirect(1);
58          Field addressField;
59          try {
60              addressField = Buffer.class.getDeclaredField("address");
61              addressField.setAccessible(true);
62              if (addressField.getLong(ByteBuffer.allocate(1)) != 0) {
63                  // A heap buffer must have 0 address.
64                  addressField = null;
65              } else {
66                  if (addressField.getLong(direct) == 0) {
67                      // A direct buffer must have non-zero address.
68                      addressField = null;
69                  }
70              }
71          } catch (Throwable t) {
72              // Failed to access the address field.
73              addressField = null;
74          }
75          logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
76  
77          Unsafe unsafe;
78          if (addressField != null) {
79              try {
80                  Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
81                  unsafeField.setAccessible(true);
82                  unsafe = (Unsafe) unsafeField.get(null);
83                  logger.debug("sun.misc.Unsafe.theUnsafe: {}", unsafe != null ? "available" : "unavailable");
84  
85                  // Ensure the unsafe supports all necessary methods to work around the mistake in the latest OpenJDK.
86                  // https://github.com/netty/netty/issues/1061
87                  // http://www.mail-archive.com/[email protected]/msg00698.html
88                  try {
89                      if (unsafe != null) {
90                          unsafe.getClass().getDeclaredMethod(
91                                  "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
92                          logger.debug("sun.misc.Unsafe.copyMemory: available");
93                      }
94                  } catch (NoSuchMethodError t) {
95                      logger.debug("sun.misc.Unsafe.copyMemory: unavailable");
96                      throw t;
97                  } catch (NoSuchMethodException e) {
98                      logger.debug("sun.misc.Unsafe.copyMemory: unavailable");
99                      throw e;
100                 }
101             } catch (Throwable cause) {
102                 // Unsafe.copyMemory(Object, long, Object, long, long) unavailable.
103                 unsafe = null;
104             }
105         } else {
106             // If we cannot access the address of a direct buffer, there's no point of using unsafe.
107             // Let's just pretend unsafe is unavailable for overall simplicity.
108             unsafe = null;
109         }
110 
111         UNSAFE = unsafe;
112 
113         if (unsafe == null) {
114             ADDRESS_FIELD_OFFSET = -1;
115             UNALIGNED = false;
116         } else {
117             ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
118             boolean unaligned;
119             try {
120                 Class<?> bitsClass = Class.forName("java.nio.Bits", false, ClassLoader.getSystemClassLoader());
121                 Method unalignedMethod = bitsClass.getDeclaredMethod("unaligned");
122                 unalignedMethod.setAccessible(true);
123                 unaligned = Boolean.TRUE.equals(unalignedMethod.invoke(null));
124             } catch (Throwable t) {
125                 // We at least know x86 and x64 support unaligned access.
126                 String arch = SystemPropertyUtil.get("os.arch", "");
127                 //noinspection DynamicRegexReplaceableByCompiledPattern
128                 unaligned = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64)$");
129             }
130 
131             UNALIGNED = unaligned;
132             logger.debug("java.nio.Bits.unaligned: {}", UNALIGNED);
133         }
134     }
135 
136     static boolean hasUnsafe() {
137         return UNSAFE != null;
138     }
139 
140     static void throwException(Throwable t) {
141         UNSAFE.throwException(t);
142     }
143 
144     static void freeDirectBuffer(ByteBuffer buffer) {
145         // Delegate to other class to not break on android
146         // See https://github.com/netty/netty/issues/2604
147         Cleaner0.freeDirectBuffer(buffer);
148     }
149 
150     static long directBufferAddress(ByteBuffer buffer) {
151         return getLong(buffer, ADDRESS_FIELD_OFFSET);
152     }
153 
154     static long arrayBaseOffset() {
155         return UNSAFE.arrayBaseOffset(byte[].class);
156     }
157 
158     static Object getObject(Object object, long fieldOffset) {
159         return UNSAFE.getObject(object, fieldOffset);
160     }
161 
162     static Object getObjectVolatile(Object object, long fieldOffset) {
163         return UNSAFE.getObjectVolatile(object, fieldOffset);
164     }
165 
166     static int getInt(Object object, long fieldOffset) {
167         return UNSAFE.getInt(object, fieldOffset);
168     }
169 
170     private static long getLong(Object object, long fieldOffset) {
171         return UNSAFE.getLong(object, fieldOffset);
172     }
173 
174     static long objectFieldOffset(Field field) {
175         return UNSAFE.objectFieldOffset(field);
176     }
177 
178     static byte getByte(long address) {
179         return UNSAFE.getByte(address);
180     }
181 
182     static short getShort(long address) {
183         if (UNALIGNED) {
184             return UNSAFE.getShort(address);
185         } else if (BIG_ENDIAN) {
186             return (short) (getByte(address) << 8 | getByte(address + 1) & 0xff);
187         } else {
188             return (short) (getByte(address + 1) << 8 | getByte(address) & 0xff);
189         }
190     }
191 
192     static int getInt(long address) {
193         if (UNALIGNED) {
194             return UNSAFE.getInt(address);
195         } else if (BIG_ENDIAN) {
196             return getByte(address) << 24 |
197                   (getByte(address + 1) & 0xff) << 16 |
198                   (getByte(address + 2) & 0xff) <<  8 |
199                    getByte(address + 3) & 0xff;
200         } else {
201             return getByte(address + 3) << 24 |
202                   (getByte(address + 2) & 0xff) << 16 |
203                   (getByte(address + 1) & 0xff) <<  8 |
204                    getByte(address) & 0xff;
205         }
206     }
207 
208     static long getLong(long address) {
209         if (UNALIGNED) {
210             return UNSAFE.getLong(address);
211         } else if (BIG_ENDIAN) {
212             return (long) getByte(address) << 56 |
213                   ((long) getByte(address + 1) & 0xff) << 48 |
214                   ((long) getByte(address + 2) & 0xff) << 40 |
215                   ((long) getByte(address + 3) & 0xff) << 32 |
216                   ((long) getByte(address + 4) & 0xff) << 24 |
217                   ((long) getByte(address + 5) & 0xff) << 16 |
218                   ((long) getByte(address + 6) & 0xff) <<  8 |
219                    (long) getByte(address + 7) & 0xff;
220         } else {
221             return (long) getByte(address + 7) << 56 |
222                   ((long) getByte(address + 6) & 0xff) << 48 |
223                   ((long) getByte(address + 5) & 0xff) << 40 |
224                   ((long) getByte(address + 4) & 0xff) << 32 |
225                   ((long) getByte(address + 3) & 0xff) << 24 |
226                   ((long) getByte(address + 2) & 0xff) << 16 |
227                   ((long) getByte(address + 1) & 0xff) <<  8 |
228                    (long) getByte(address) & 0xff;
229         }
230     }
231 
232     static void putOrderedObject(Object object, long address, Object value) {
233         UNSAFE.putOrderedObject(object, address, value);
234     }
235 
236     static void putByte(long address, byte value) {
237         UNSAFE.putByte(address, value);
238     }
239 
240     static void putShort(long address, short value) {
241         if (UNALIGNED) {
242             UNSAFE.putShort(address, value);
243         } else if (BIG_ENDIAN) {
244             putByte(address, (byte) (value >>> 8));
245             putByte(address + 1, (byte) value);
246         } else {
247             putByte(address + 1, (byte) (value >>> 8));
248             putByte(address, (byte) value);
249         }
250     }
251 
252     static void putInt(long address, int value) {
253         if (UNALIGNED) {
254             UNSAFE.putInt(address, value);
255         } else if (BIG_ENDIAN) {
256             putByte(address, (byte) (value >>> 24));
257             putByte(address + 1, (byte) (value >>> 16));
258             putByte(address + 2, (byte) (value >>> 8));
259             putByte(address + 3, (byte) value);
260         } else {
261             putByte(address + 3, (byte) (value >>> 24));
262             putByte(address + 2, (byte) (value >>> 16));
263             putByte(address + 1, (byte) (value >>> 8));
264             putByte(address, (byte) value);
265         }
266     }
267 
268     static void putLong(long address, long value) {
269         if (UNALIGNED) {
270             UNSAFE.putLong(address, value);
271         } else if (BIG_ENDIAN) {
272             putByte(address, (byte) (value >>> 56));
273             putByte(address + 1, (byte) (value >>> 48));
274             putByte(address + 2, (byte) (value >>> 40));
275             putByte(address + 3, (byte) (value >>> 32));
276             putByte(address + 4, (byte) (value >>> 24));
277             putByte(address + 5, (byte) (value >>> 16));
278             putByte(address + 6, (byte) (value >>> 8));
279             putByte(address + 7, (byte) value);
280         } else {
281             putByte(address + 7, (byte) (value >>> 56));
282             putByte(address + 6, (byte) (value >>> 48));
283             putByte(address + 5, (byte) (value >>> 40));
284             putByte(address + 4, (byte) (value >>> 32));
285             putByte(address + 3, (byte) (value >>> 24));
286             putByte(address + 2, (byte) (value >>> 16));
287             putByte(address + 1, (byte) (value >>> 8));
288             putByte(address, (byte) value);
289         }
290     }
291 
292     static void copyMemory(long srcAddr, long dstAddr, long length) {
293         //UNSAFE.copyMemory(srcAddr, dstAddr, length);
294         while (length > 0) {
295             long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
296             UNSAFE.copyMemory(srcAddr, dstAddr, size);
297             length -= size;
298             srcAddr += size;
299             dstAddr += size;
300         }
301     }
302 
303     static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
304         //UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
305         while (length > 0) {
306             long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
307             UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
308             length -= size;
309             srcOffset += size;
310             dstOffset += size;
311         }
312     }
313 
314     static <U, W> AtomicReferenceFieldUpdater<U, W> newAtomicReferenceFieldUpdater(
315             Class<U> tclass, String fieldName) throws Exception {
316         return new UnsafeAtomicReferenceFieldUpdater<U, W>(UNSAFE, tclass, fieldName);
317     }
318 
319     static <T> AtomicIntegerFieldUpdater<T> newAtomicIntegerFieldUpdater(
320             Class<?> tclass, String fieldName) throws Exception {
321         return new UnsafeAtomicIntegerFieldUpdater<T>(UNSAFE, tclass, fieldName);
322     }
323 
324     static <T> AtomicLongFieldUpdater<T> newAtomicLongFieldUpdater(
325             Class<?> tclass, String fieldName) throws Exception {
326         return new UnsafeAtomicLongFieldUpdater<T>(UNSAFE, tclass, fieldName);
327     }
328 
329     static ClassLoader getClassLoader(final Class<?> clazz) {
330         if (System.getSecurityManager() == null) {
331             return clazz.getClassLoader();
332         } else {
333             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
334                 @Override
335                 public ClassLoader run() {
336                     return clazz.getClassLoader();
337                 }
338             });
339         }
340     }
341 
342     static ClassLoader getContextClassLoader() {
343         if (System.getSecurityManager() == null) {
344             return Thread.currentThread().getContextClassLoader();
345         } else {
346             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
347                 @Override
348                 public ClassLoader run() {
349                     return Thread.currentThread().getContextClassLoader();
350                 }
351             });
352         }
353     }
354 
355     static ClassLoader getSystemClassLoader() {
356         if (System.getSecurityManager() == null) {
357             return ClassLoader.getSystemClassLoader();
358         } else {
359             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
360                 @Override
361                 public ClassLoader run() {
362                     return ClassLoader.getSystemClassLoader();
363                 }
364             });
365         }
366     }
367 
368     static int addressSize() {
369         return UNSAFE.addressSize();
370     }
371 
372     static long allocateMemory(long size) {
373         return UNSAFE.allocateMemory(size);
374     }
375 
376     static void freeMemory(long address) {
377         UNSAFE.freeMemory(address);
378     }
379 
380     private PlatformDependent0() {
381     }
382 
383 }