查看本类的 API文档回源码主页即时通讯网 - 即时通讯开发者社区!
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    *   https://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.Constructor;
23  import java.lang.reflect.Field;
24  import java.lang.reflect.InvocationTargetException;
25  import java.lang.reflect.Method;
26  import java.nio.Buffer;
27  import java.nio.ByteBuffer;
28  import java.security.AccessController;
29  import java.security.PrivilegedAction;
30  import java.util.concurrent.atomic.AtomicLong;
31  
32  import static io.netty.util.internal.ObjectUtil.checkNotNull;
33  
34  /**
35   * The {@link PlatformDependent} operations which requires access to {@code sun.misc.*}.
36   */
37  @SuppressJava6Requirement(reason = "Unsafe access is guarded")
38  final class PlatformDependent0 {
39  
40      private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
41      private static final long ADDRESS_FIELD_OFFSET;
42      private static final long BYTE_ARRAY_BASE_OFFSET;
43      private static final long INT_ARRAY_BASE_OFFSET;
44      private static final long INT_ARRAY_INDEX_SCALE;
45      private static final long LONG_ARRAY_BASE_OFFSET;
46      private static final long LONG_ARRAY_INDEX_SCALE;
47      private static final Constructor<?> DIRECT_BUFFER_CONSTRUCTOR;
48      private static final Throwable EXPLICIT_NO_UNSAFE_CAUSE = explicitNoUnsafeCause0();
49      private static final Method ALLOCATE_ARRAY_METHOD;
50      private static final Method ALIGN_SLICE;
51      private static final int JAVA_VERSION = javaVersion0();
52      private static final boolean IS_ANDROID = isAndroid0();
53      private static final boolean STORE_FENCE_AVAILABLE;
54  
55      private static final Throwable UNSAFE_UNAVAILABILITY_CAUSE;
56      private static final Object INTERNAL_UNSAFE;
57  
58      // See https://github.com/oracle/graal/blob/master/sdk/src/org.graalvm.nativeimage/src/org/graalvm/nativeimage/
59      // ImageInfo.java
60      private static final boolean RUNNING_IN_NATIVE_IMAGE = SystemPropertyUtil.contains(
61              "org.graalvm.nativeimage.imagecode");
62  
63      private static final boolean IS_EXPLICIT_TRY_REFLECTION_SET_ACCESSIBLE = explicitTryReflectionSetAccessible0();
64  
65      static final Unsafe UNSAFE;
66  
67      // constants borrowed from murmur3
68      static final int HASH_CODE_ASCII_SEED = 0xc2b2ae35;
69      static final int HASH_CODE_C1 = 0xcc9e2d51;
70      static final int HASH_CODE_C2 = 0x1b873593;
71  
72      /**
73       * Limits the number of bytes to copy per {@link Unsafe#copyMemory(long, long, long)} to allow safepoint polling
74       * during a large copy.
75       */
76      private static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
77  
78      private static final boolean UNALIGNED;
79  
80      private static final long BITS_MAX_DIRECT_MEMORY;
81  
82      static {
83          final ByteBuffer direct;
84          Field addressField = null;
85          Method allocateArrayMethod = null;
86          Throwable unsafeUnavailabilityCause = null;
87          Unsafe unsafe;
88          Object internalUnsafe = null;
89          boolean storeFenceAvailable = false;
90          if ((unsafeUnavailabilityCause = EXPLICIT_NO_UNSAFE_CAUSE) != null) {
91              direct = null;
92              addressField = null;
93              unsafe = null;
94              internalUnsafe = null;
95          } else {
96              direct = ByteBuffer.allocateDirect(1);
97  
98              // attempt to access field Unsafe#theUnsafe
99              final Object maybeUnsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
100                 @Override
101                 public Object run() {
102                     try {
103                         final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
104                         // We always want to try using Unsafe as the access still works on java9 as well and
105                         // we need it for out native-transports and many optimizations.
106                         Throwable cause = ReflectionUtil.trySetAccessible(unsafeField, false);
107                         if (cause != null) {
108                             return cause;
109                         }
110                         // the unsafe instance
111                         return unsafeField.get(null);
112                     } catch (NoSuchFieldException e) {
113                         return e;
114                     } catch (SecurityException e) {
115                         return e;
116                     } catch (IllegalAccessException e) {
117                         return e;
118                     } catch (NoClassDefFoundError e) {
119                         // Also catch NoClassDefFoundError in case someone uses for example OSGI and it made
120                         // Unsafe unloadable.
121                         return e;
122                     }
123                 }
124             });
125 
126             // the conditional check here can not be replaced with checking that maybeUnsafe
127             // is an instanceof Unsafe and reversing the if and else blocks; this is because an
128             // instanceof check against Unsafe will trigger a class load and we might not have
129             // the runtime permission accessClassInPackage.sun.misc
130             if (maybeUnsafe instanceof Throwable) {
131                 unsafe = null;
132                 unsafeUnavailabilityCause = (Throwable) maybeUnsafe;
133                 if (logger.isTraceEnabled()) {
134                     logger.debug("sun.misc.Unsafe.theUnsafe: unavailable", (Throwable) maybeUnsafe);
135                 } else {
136                     logger.debug("sun.misc.Unsafe.theUnsafe: unavailable: {}", ((Throwable) maybeUnsafe).getMessage());
137                 }
138             } else {
139                 unsafe = (Unsafe) maybeUnsafe;
140                 logger.debug("sun.misc.Unsafe.theUnsafe: available");
141             }
142 
143             // ensure the unsafe supports all necessary methods to work around the mistake in the latest OpenJDK
144             // https://github.com/netty/netty/issues/1061
145             // https://www.mail-archive.com/jdk6-dev@openjdk.java.net/msg00698.html
146             if (unsafe != null) {
147                 final Unsafe finalUnsafe = unsafe;
148                 final Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
149                     @Override
150                     public Object run() {
151                         try {
152                             finalUnsafe.getClass().getDeclaredMethod(
153                                     "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
154                             return null;
155                         } catch (NoSuchMethodException e) {
156                             return e;
157                         } catch (SecurityException e) {
158                             return e;
159                         }
160                     }
161                 });
162 
163                 if (maybeException == null) {
164                     logger.debug("sun.misc.Unsafe.copyMemory: available");
165                 } else {
166                     // Unsafe.copyMemory(Object, long, Object, long, long) unavailable.
167                     unsafe = null;
168                     unsafeUnavailabilityCause = (Throwable) maybeException;
169                     if (logger.isTraceEnabled()) {
170                         logger.debug("sun.misc.Unsafe.copyMemory: unavailable", (Throwable) maybeException);
171                     } else {
172                         logger.debug("sun.misc.Unsafe.copyMemory: unavailable: {}",
173                                 ((Throwable) maybeException).getMessage());
174                     }
175                 }
176             }
177 
178             // ensure Unsafe::storeFence to be available: jdk < 8 shouldn't have it
179             if (unsafe != null) {
180                 final Unsafe finalUnsafe = unsafe;
181                 final Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
182                     @Override
183                     public Object run() {
184                         try {
185                             finalUnsafe.getClass().getDeclaredMethod("storeFence");
186                             return null;
187                         } catch (NoSuchMethodException e) {
188                             return e;
189                         } catch (SecurityException e) {
190                             return e;
191                         }
192                     }
193                 });
194 
195                 if (maybeException == null) {
196                     logger.debug("sun.misc.Unsafe.storeFence: available");
197                     storeFenceAvailable = true;
198                 } else {
199                     storeFenceAvailable = false;
200                     // Unsafe.storeFence unavailable.
201                     if (logger.isTraceEnabled()) {
202                         logger.debug("sun.misc.Unsafe.storeFence: unavailable", (Throwable) maybeException);
203                     } else {
204                         logger.debug("sun.misc.Unsafe.storeFence: unavailable: {}",
205                                      ((Throwable) maybeException).getMessage());
206                     }
207                 }
208             }
209 
210             if (unsafe != null) {
211                 final Unsafe finalUnsafe = unsafe;
212 
213                 // attempt to access field Buffer#address
214                 final Object maybeAddressField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
215                     @Override
216                     public Object run() {
217                         try {
218                             final Field field = Buffer.class.getDeclaredField("address");
219                             // Use Unsafe to read value of the address field. This way it will not fail on JDK9+ which
220                             // will forbid changing the access level via reflection.
221                             final long offset = finalUnsafe.objectFieldOffset(field);
222                             final long address = finalUnsafe.getLong(direct, offset);
223 
224                             // if direct really is a direct buffer, address will be non-zero
225                             if (address == 0) {
226                                 return null;
227                             }
228                             return field;
229                         } catch (NoSuchFieldException e) {
230                             return e;
231                         } catch (SecurityException e) {
232                             return e;
233                         }
234                     }
235                 });
236 
237                 if (maybeAddressField instanceof Field) {
238                     addressField = (Field) maybeAddressField;
239                     logger.debug("java.nio.Buffer.address: available");
240                 } else {
241                     unsafeUnavailabilityCause = (Throwable) maybeAddressField;
242                     if (logger.isTraceEnabled()) {
243                         logger.debug("java.nio.Buffer.address: unavailable", (Throwable) maybeAddressField);
244                     } else {
245                         logger.debug("java.nio.Buffer.address: unavailable: {}",
246                                 ((Throwable) maybeAddressField).getMessage());
247                     }
248 
249                     // If we cannot access the address of a direct buffer, there's no point of using unsafe.
250                     // Let's just pretend unsafe is unavailable for overall simplicity.
251                     unsafe = null;
252                 }
253             }
254 
255             if (unsafe != null) {
256                 // There are assumptions made where ever BYTE_ARRAY_BASE_OFFSET is used (equals, hashCodeAscii, and
257                 // primitive accessors) that arrayIndexScale == 1, and results are undefined if this is not the case.
258                 long byteArrayIndexScale = unsafe.arrayIndexScale(byte[].class);
259                 if (byteArrayIndexScale != 1) {
260                     logger.debug("unsafe.arrayIndexScale is {} (expected: 1). Not using unsafe.", byteArrayIndexScale);
261                     unsafeUnavailabilityCause = new UnsupportedOperationException("Unexpected unsafe.arrayIndexScale");
262                     unsafe = null;
263                 }
264             }
265         }
266         UNSAFE_UNAVAILABILITY_CAUSE = unsafeUnavailabilityCause;
267         UNSAFE = unsafe;
268 
269         if (unsafe == null) {
270             ADDRESS_FIELD_OFFSET = -1;
271             BYTE_ARRAY_BASE_OFFSET = -1;
272             LONG_ARRAY_BASE_OFFSET = -1;
273             LONG_ARRAY_INDEX_SCALE = -1;
274             INT_ARRAY_BASE_OFFSET = -1;
275             INT_ARRAY_INDEX_SCALE = -1;
276             UNALIGNED = false;
277             BITS_MAX_DIRECT_MEMORY = -1;
278             DIRECT_BUFFER_CONSTRUCTOR = null;
279             ALLOCATE_ARRAY_METHOD = null;
280             STORE_FENCE_AVAILABLE = false;
281         } else {
282             Constructor<?> directBufferConstructor;
283             long address = -1;
284             try {
285                 final Object maybeDirectBufferConstructor =
286                         AccessController.doPrivileged(new PrivilegedAction<Object>() {
287                             @Override
288                             public Object run() {
289                                 try {
290                                     final Constructor<?> constructor = javaVersion() >= 21 ?
291                                             direct.getClass().getDeclaredConstructor(long.class, long.class) :
292                                             direct.getClass().getDeclaredConstructor(long.class, int.class);
293                                     Throwable cause = ReflectionUtil.trySetAccessible(constructor, true);
294                                     if (cause != null) {
295                                         return cause;
296                                     }
297                                     return constructor;
298                                 } catch (NoSuchMethodException e) {
299                                     return e;
300                                 } catch (SecurityException e) {
301                                     return e;
302                                 }
303                             }
304                         });
305 
306                 if (maybeDirectBufferConstructor instanceof Constructor<?>) {
307                     address = UNSAFE.allocateMemory(1);
308                     // try to use the constructor now
309                     try {
310                         ((Constructor<?>) maybeDirectBufferConstructor).newInstance(address, 1);
311                         directBufferConstructor = (Constructor<?>) maybeDirectBufferConstructor;
312                         logger.debug("direct buffer constructor: available");
313                     } catch (InstantiationException e) {
314                         directBufferConstructor = null;
315                     } catch (IllegalAccessException e) {
316                         directBufferConstructor = null;
317                     } catch (InvocationTargetException e) {
318                         directBufferConstructor = null;
319                     }
320                 } else {
321                     if (logger.isTraceEnabled()) {
322                         logger.debug("direct buffer constructor: unavailable",
323                                 (Throwable) maybeDirectBufferConstructor);
324                     } else {
325                         logger.debug("direct buffer constructor: unavailable: {}",
326                                 ((Throwable) maybeDirectBufferConstructor).getMessage());
327                     }
328                     directBufferConstructor = null;
329                 }
330             } finally {
331                 if (address != -1) {
332                     UNSAFE.freeMemory(address);
333                 }
334             }
335             DIRECT_BUFFER_CONSTRUCTOR = directBufferConstructor;
336             ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
337             BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
338             INT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
339             INT_ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale(int[].class);
340             LONG_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(long[].class);
341             LONG_ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale(long[].class);
342             final boolean unaligned;
343             // using a known type to avoid loading new classes
344             final AtomicLong maybeMaxMemory = new AtomicLong(-1);
345             Object maybeUnaligned = AccessController.doPrivileged(new PrivilegedAction<Object>() {
346                 @Override
347                 public Object run() {
348                     try {
349                         Class<?> bitsClass =
350                                 Class.forName("java.nio.Bits", false, getSystemClassLoader());
351                         int version = javaVersion();
352                         if (unsafeStaticFieldOffsetSupported() && version >= 9) {
353                             // Java9/10 use all lowercase and later versions all uppercase.
354                             String fieldName = version >= 11? "MAX_MEMORY" : "maxMemory";
355                             // On Java9 and later we try to directly access the field as we can do this without
356                             // adjust the accessible levels.
357                             try {
358                                 Field maxMemoryField = bitsClass.getDeclaredField(fieldName);
359                                 if (maxMemoryField.getType() == long.class) {
360                                     long offset = UNSAFE.staticFieldOffset(maxMemoryField);
361                                     Object object = UNSAFE.staticFieldBase(maxMemoryField);
362                                     maybeMaxMemory.lazySet(UNSAFE.getLong(object, offset));
363                                 }
364                             } catch (Throwable ignore) {
365                                 // ignore if can't access
366                             }
367                             fieldName = version >= 11? "UNALIGNED" : "unaligned";
368                             try {
369                                 Field unalignedField = bitsClass.getDeclaredField(fieldName);
370                                 if (unalignedField.getType() == boolean.class) {
371                                     long offset = UNSAFE.staticFieldOffset(unalignedField);
372                                     Object object = UNSAFE.staticFieldBase(unalignedField);
373                                     return UNSAFE.getBoolean(object, offset);
374                                 }
375                                 // There is something unexpected stored in the field,
376                                 // let us fall-back and try to use a reflective method call as last resort.
377                             } catch (NoSuchFieldException ignore) {
378                                 // We did not find the field we expected, move on.
379                             }
380                         }
381                         Method unalignedMethod = bitsClass.getDeclaredMethod("unaligned");
382                         Throwable cause = ReflectionUtil.trySetAccessible(unalignedMethod, true);
383                         if (cause != null) {
384                             return cause;
385                         }
386                         return unalignedMethod.invoke(null);
387                     } catch (NoSuchMethodException e) {
388                         return e;
389                     } catch (SecurityException e) {
390                         return e;
391                     } catch (IllegalAccessException e) {
392                         return e;
393                     } catch (ClassNotFoundException e) {
394                         return e;
395                     } catch (InvocationTargetException e) {
396                         return e;
397                     }
398                 }
399             });
400 
401             if (maybeUnaligned instanceof Boolean) {
402                 unaligned = (Boolean) maybeUnaligned;
403                 logger.debug("java.nio.Bits.unaligned: available, {}", unaligned);
404             } else {
405                 String arch = SystemPropertyUtil.get("os.arch", "");
406                 //noinspection DynamicRegexReplaceableByCompiledPattern
407                 unaligned = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64)$");
408                 Throwable t = (Throwable) maybeUnaligned;
409                 if (logger.isTraceEnabled()) {
410                     logger.debug("java.nio.Bits.unaligned: unavailable, {}", unaligned, t);
411                 } else {
412                     logger.debug("java.nio.Bits.unaligned: unavailable, {}, {}", unaligned, t.getMessage());
413                 }
414             }
415 
416             UNALIGNED = unaligned;
417             BITS_MAX_DIRECT_MEMORY = maybeMaxMemory.get() >= 0? maybeMaxMemory.get() : -1;
418 
419             if (javaVersion() >= 9) {
420                 Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
421                     @Override
422                     public Object run() {
423                         try {
424                             // Java9 has jdk.internal.misc.Unsafe and not all methods are propagated to
425                             // sun.misc.Unsafe
426                             Class<?> internalUnsafeClass = getClassLoader(PlatformDependent0.class)
427                                     .loadClass("jdk.internal.misc.Unsafe");
428                             Method method = internalUnsafeClass.getDeclaredMethod("getUnsafe");
429                             return method.invoke(null);
430                         } catch (Throwable e) {
431                             return e;
432                         }
433                     }
434                 });
435                 if (!(maybeException instanceof Throwable)) {
436                     internalUnsafe = maybeException;
437                     final Object finalInternalUnsafe = internalUnsafe;
438                     maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
439                         @Override
440                         public Object run() {
441                             try {
442                                 return finalInternalUnsafe.getClass().getDeclaredMethod(
443                                         "allocateUninitializedArray", Class.class, int.class);
444                             } catch (NoSuchMethodException e) {
445                                 return e;
446                             } catch (SecurityException e) {
447                                 return e;
448                             }
449                         }
450                     });
451 
452                     if (maybeException instanceof Method) {
453                         try {
454                             Method m = (Method) maybeException;
455                             byte[] bytes = (byte[]) m.invoke(finalInternalUnsafe, byte.class, 8);
456                             assert bytes.length == 8;
457                             allocateArrayMethod = m;
458                         } catch (IllegalAccessException e) {
459                             maybeException = e;
460                         } catch (InvocationTargetException e) {
461                             maybeException = e;
462                         }
463                     }
464                 }
465 
466                 if (maybeException instanceof Throwable) {
467                     if (logger.isTraceEnabled()) {
468                         logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable",
469                                 (Throwable) maybeException);
470                     } else {
471                         logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable: {}",
472                                 ((Throwable) maybeException).getMessage());
473                     }
474                 } else {
475                     logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): available");
476                 }
477             } else {
478                 logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable prior to Java9");
479             }
480             ALLOCATE_ARRAY_METHOD = allocateArrayMethod;
481             STORE_FENCE_AVAILABLE = storeFenceAvailable;
482         }
483 
484         if (javaVersion() > 9) {
485             ALIGN_SLICE = (Method) AccessController.doPrivileged(new PrivilegedAction<Object>() {
486                 @Override
487                 public Object run() {
488                     try {
489                         return ByteBuffer.class.getDeclaredMethod("alignedSlice", int.class);
490                     } catch (Exception e) {
491                         return null;
492                     }
493                 }
494             });
495         } else {
496             ALIGN_SLICE = null;
497         }
498 
499         INTERNAL_UNSAFE = internalUnsafe;
500 
501         logger.debug("java.nio.DirectByteBuffer.<init>(long, {int,long}): {}",
502                 DIRECT_BUFFER_CONSTRUCTOR != null ? "available" : "unavailable");
503     }
504 
505     private static boolean unsafeStaticFieldOffsetSupported() {
506         return !RUNNING_IN_NATIVE_IMAGE;
507     }
508 
509     static boolean isExplicitNoUnsafe() {
510         return EXPLICIT_NO_UNSAFE_CAUSE != null;
511     }
512 
513     private static Throwable explicitNoUnsafeCause0() {
514         final boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false);
515         logger.debug("-Dio.netty.noUnsafe: {}", noUnsafe);
516 
517         if (noUnsafe) {
518             logger.debug("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)");
519             return new UnsupportedOperationException("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)");
520         }
521 
522         // Legacy properties
523         String unsafePropName;
524         if (SystemPropertyUtil.contains("io.netty.tryUnsafe")) {
525             unsafePropName = "io.netty.tryUnsafe";
526         } else {
527             unsafePropName = "org.jboss.netty.tryUnsafe";
528         }
529 
530         if (!SystemPropertyUtil.getBoolean(unsafePropName, true)) {
531             String msg = "sun.misc.Unsafe: unavailable (" + unsafePropName + ")";
532             logger.debug(msg);
533             return new UnsupportedOperationException(msg);
534         }
535 
536         return null;
537     }
538 
539     static boolean isUnaligned() {
540         return UNALIGNED;
541     }
542 
543     /**
544      * Any value >= 0 should be considered as a valid max direct memory value.
545      */
546     static long bitsMaxDirectMemory() {
547         return BITS_MAX_DIRECT_MEMORY;
548     }
549 
550     static boolean hasUnsafe() {
551         return UNSAFE != null;
552     }
553 
554     static Throwable getUnsafeUnavailabilityCause() {
555         return UNSAFE_UNAVAILABILITY_CAUSE;
556     }
557 
558     static boolean unalignedAccess() {
559         return UNALIGNED;
560     }
561 
562     static void throwException(Throwable cause) {
563         // JVM has been observed to crash when passing a null argument. See https://github.com/netty/netty/issues/4131.
564         UNSAFE.throwException(checkNotNull(cause, "cause"));
565     }
566 
567     static boolean hasDirectBufferNoCleanerConstructor() {
568         return DIRECT_BUFFER_CONSTRUCTOR != null;
569     }
570 
571     static ByteBuffer reallocateDirectNoCleaner(ByteBuffer buffer, int capacity) {
572         return newDirectBuffer(UNSAFE.reallocateMemory(directBufferAddress(buffer), capacity), capacity);
573     }
574 
575     static ByteBuffer allocateDirectNoCleaner(int capacity) {
576         // Calling malloc with capacity of 0 may return a null ptr or a memory address that can be used.
577         // Just use 1 to make it safe to use in all cases:
578         // See: https://pubs.opengroup.org/onlinepubs/009695399/functions/malloc.html
579         return newDirectBuffer(UNSAFE.allocateMemory(Math.max(1, capacity)), capacity);
580     }
581 
582     static boolean hasAlignSliceMethod() {
583         return ALIGN_SLICE != null;
584     }
585 
586     static ByteBuffer alignSlice(ByteBuffer buffer, int alignment) {
587         try {
588             return (ByteBuffer) ALIGN_SLICE.invoke(buffer, alignment);
589         } catch (IllegalAccessException e) {
590             throw new Error(e);
591         } catch (InvocationTargetException e) {
592             throw new Error(e);
593         }
594     }
595 
596     static boolean hasAllocateArrayMethod() {
597         return ALLOCATE_ARRAY_METHOD != null;
598     }
599 
600     static byte[] allocateUninitializedArray(int size) {
601         try {
602             return (byte[]) ALLOCATE_ARRAY_METHOD.invoke(INTERNAL_UNSAFE, byte.class, size);
603         } catch (IllegalAccessException e) {
604             throw new Error(e);
605         } catch (InvocationTargetException e) {
606             throw new Error(e);
607         }
608     }
609 
610     static ByteBuffer newDirectBuffer(long address, int capacity) {
611         ObjectUtil.checkPositiveOrZero(capacity, "capacity");
612 
613         try {
614             return (ByteBuffer) DIRECT_BUFFER_CONSTRUCTOR.newInstance(address, capacity);
615         } catch (Throwable cause) {
616             // Not expected to ever throw!
617             if (cause instanceof Error) {
618                 throw (Error) cause;
619             }
620             throw new Error(cause);
621         }
622     }
623 
624     static long directBufferAddress(ByteBuffer buffer) {
625         return getLong(buffer, ADDRESS_FIELD_OFFSET);
626     }
627 
628     static long byteArrayBaseOffset() {
629         return BYTE_ARRAY_BASE_OFFSET;
630     }
631 
632     static Object getObject(Object object, long fieldOffset) {
633         return UNSAFE.getObject(object, fieldOffset);
634     }
635 
636     static int getInt(Object object, long fieldOffset) {
637         return UNSAFE.getInt(object, fieldOffset);
638     }
639 
640     static void safeConstructPutInt(Object object, long fieldOffset, int value) {
641         if (STORE_FENCE_AVAILABLE) {
642             UNSAFE.putInt(object, fieldOffset, value);
643             UNSAFE.storeFence();
644         } else {
645             UNSAFE.putIntVolatile(object, fieldOffset, value);
646         }
647     }
648 
649     private static long getLong(Object object, long fieldOffset) {
650         return UNSAFE.getLong(object, fieldOffset);
651     }
652 
653     static long objectFieldOffset(Field field) {
654         return UNSAFE.objectFieldOffset(field);
655     }
656 
657     static byte getByte(long address) {
658         return UNSAFE.getByte(address);
659     }
660 
661     static short getShort(long address) {
662         return UNSAFE.getShort(address);
663     }
664 
665     static int getInt(long address) {
666         return UNSAFE.getInt(address);
667     }
668 
669     static long getLong(long address) {
670         return UNSAFE.getLong(address);
671     }
672 
673     static byte getByte(byte[] data, int index) {
674         return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
675     }
676 
677     static byte getByte(byte[] data, long index) {
678         return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
679     }
680 
681     static short getShort(byte[] data, int index) {
682         return UNSAFE.getShort(data, BYTE_ARRAY_BASE_OFFSET + index);
683     }
684 
685     static int getInt(byte[] data, int index) {
686         return UNSAFE.getInt(data, BYTE_ARRAY_BASE_OFFSET + index);
687     }
688 
689     static int getInt(int[] data, long index) {
690         return UNSAFE.getInt(data, INT_ARRAY_BASE_OFFSET + INT_ARRAY_INDEX_SCALE * index);
691     }
692 
693     static int getIntVolatile(long address) {
694         return UNSAFE.getIntVolatile(null, address);
695     }
696 
697     static void putIntOrdered(long adddress, int newValue) {
698         UNSAFE.putOrderedInt(null, adddress, newValue);
699     }
700 
701     static long getLong(byte[] data, int index) {
702         return UNSAFE.getLong(data, BYTE_ARRAY_BASE_OFFSET + index);
703     }
704 
705     static long getLong(long[] data, long index) {
706         return UNSAFE.getLong(data, LONG_ARRAY_BASE_OFFSET + LONG_ARRAY_INDEX_SCALE * index);
707     }
708 
709     static void putByte(long address, byte value) {
710         UNSAFE.putByte(address, value);
711     }
712 
713     static void putShort(long address, short value) {
714         UNSAFE.putShort(address, value);
715     }
716 
717     static void putInt(long address, int value) {
718         UNSAFE.putInt(address, value);
719     }
720 
721     static void putLong(long address, long value) {
722         UNSAFE.putLong(address, value);
723     }
724 
725     static void putByte(byte[] data, int index, byte value) {
726         UNSAFE.putByte(data, BYTE_ARRAY_BASE_OFFSET + index, value);
727     }
728 
729     static void putByte(Object data, long offset, byte value) {
730         UNSAFE.putByte(data, offset, value);
731     }
732 
733     static void putShort(byte[] data, int index, short value) {
734         UNSAFE.putShort(data, BYTE_ARRAY_BASE_OFFSET + index, value);
735     }
736 
737     static void putInt(byte[] data, int index, int value) {
738         UNSAFE.putInt(data, BYTE_ARRAY_BASE_OFFSET + index, value);
739     }
740 
741     static void putLong(byte[] data, int index, long value) {
742         UNSAFE.putLong(data, BYTE_ARRAY_BASE_OFFSET + index, value);
743     }
744 
745     static void putObject(Object o, long offset, Object x) {
746         UNSAFE.putObject(o, offset, x);
747     }
748 
749     static void copyMemory(long srcAddr, long dstAddr, long length) {
750         // Manual safe-point polling is only needed prior Java9:
751         // See https://bugs.openjdk.java.net/browse/JDK-8149596
752         if (javaVersion() <= 8) {
753             copyMemoryWithSafePointPolling(srcAddr, dstAddr, length);
754         } else {
755             UNSAFE.copyMemory(srcAddr, dstAddr, length);
756         }
757     }
758 
759     private static void copyMemoryWithSafePointPolling(long srcAddr, long dstAddr, long length) {
760         while (length > 0) {
761             long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
762             UNSAFE.copyMemory(srcAddr, dstAddr, size);
763             length -= size;
764             srcAddr += size;
765             dstAddr += size;
766         }
767     }
768 
769     static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
770         // Manual safe-point polling is only needed prior Java9:
771         // See https://bugs.openjdk.java.net/browse/JDK-8149596
772         if (javaVersion() <= 8) {
773             copyMemoryWithSafePointPolling(src, srcOffset, dst, dstOffset, length);
774         } else {
775             UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
776         }
777     }
778 
779     private static void copyMemoryWithSafePointPolling(
780             Object src, long srcOffset, Object dst, long dstOffset, long length) {
781         while (length > 0) {
782             long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
783             UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
784             length -= size;
785             srcOffset += size;
786             dstOffset += size;
787         }
788     }
789 
790     static void setMemory(long address, long bytes, byte value) {
791         UNSAFE.setMemory(address, bytes, value);
792     }
793 
794     static void setMemory(Object o, long offset, long bytes, byte value) {
795         UNSAFE.setMemory(o, offset, bytes, value);
796     }
797 
798     static boolean equals(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
799         int remainingBytes = length & 7;
800         final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
801         final long diff = startPos2 - startPos1;
802         if (length >= 8) {
803             final long end = baseOffset1 + remainingBytes;
804             for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
805                 if (UNSAFE.getLong(bytes1, i) != UNSAFE.getLong(bytes2, i + diff)) {
806                     return false;
807                 }
808             }
809         }
810         if (remainingBytes >= 4) {
811             remainingBytes -= 4;
812             long pos = baseOffset1 + remainingBytes;
813             if (UNSAFE.getInt(bytes1, pos) != UNSAFE.getInt(bytes2, pos + diff)) {
814                 return false;
815             }
816         }
817         final long baseOffset2 = baseOffset1 + diff;
818         if (remainingBytes >= 2) {
819             return UNSAFE.getChar(bytes1, baseOffset1) == UNSAFE.getChar(bytes2, baseOffset2) &&
820                     (remainingBytes == 2 ||
821                     UNSAFE.getByte(bytes1, baseOffset1 + 2) == UNSAFE.getByte(bytes2, baseOffset2 + 2));
822         }
823         return remainingBytes == 0 ||
824                 UNSAFE.getByte(bytes1, baseOffset1) == UNSAFE.getByte(bytes2, baseOffset2);
825     }
826 
827     static int equalsConstantTime(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
828         long result = 0;
829         long remainingBytes = length & 7;
830         final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
831         final long end = baseOffset1 + remainingBytes;
832         final long diff = startPos2 - startPos1;
833         for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
834             result |= UNSAFE.getLong(bytes1, i) ^ UNSAFE.getLong(bytes2, i + diff);
835         }
836         if (remainingBytes >= 4) {
837             result |= UNSAFE.getInt(bytes1, baseOffset1) ^ UNSAFE.getInt(bytes2, baseOffset1 + diff);
838             remainingBytes -= 4;
839         }
840         if (remainingBytes >= 2) {
841             long pos = end - remainingBytes;
842             result |= UNSAFE.getChar(bytes1, pos) ^ UNSAFE.getChar(bytes2, pos + diff);
843             remainingBytes -= 2;
844         }
845         if (remainingBytes == 1) {
846             long pos = end - 1;
847             result |= UNSAFE.getByte(bytes1, pos) ^ UNSAFE.getByte(bytes2, pos + diff);
848         }
849         return ConstantTimeUtils.equalsConstantTime(result, 0);
850     }
851 
852     static boolean isZero(byte[] bytes, int startPos, int length) {
853         if (length <= 0) {
854             return true;
855         }
856         final long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
857         int remainingBytes = length & 7;
858         final long end = baseOffset + remainingBytes;
859         for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
860             if (UNSAFE.getLong(bytes, i) != 0) {
861                 return false;
862             }
863         }
864 
865         if (remainingBytes >= 4) {
866             remainingBytes -= 4;
867             if (UNSAFE.getInt(bytes, baseOffset + remainingBytes) != 0) {
868                 return false;
869             }
870         }
871         if (remainingBytes >= 2) {
872             return UNSAFE.getChar(bytes, baseOffset) == 0 &&
873                     (remainingBytes == 2 || bytes[startPos + 2] == 0);
874         }
875         return bytes[startPos] == 0;
876     }
877 
878     static int hashCodeAscii(byte[] bytes, int startPos, int length) {
879         int hash = HASH_CODE_ASCII_SEED;
880         long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
881         final int remainingBytes = length & 7;
882         final long end = baseOffset + remainingBytes;
883         for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
884             hash = hashCodeAsciiCompute(UNSAFE.getLong(bytes, i), hash);
885         }
886         if (remainingBytes == 0) {
887             return hash;
888         }
889         int hcConst = HASH_CODE_C1;
890         if (remainingBytes != 2 & remainingBytes != 4 & remainingBytes != 6) { // 1, 3, 5, 7
891             hash = hash * HASH_CODE_C1 + hashCodeAsciiSanitize(UNSAFE.getByte(bytes, baseOffset));
892             hcConst = HASH_CODE_C2;
893             baseOffset++;
894         }
895         if (remainingBytes != 1 & remainingBytes != 4 & remainingBytes != 5) { // 2, 3, 6, 7
896             hash = hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getShort(bytes, baseOffset));
897             hcConst = hcConst == HASH_CODE_C1 ? HASH_CODE_C2 : HASH_CODE_C1;
898             baseOffset += 2;
899         }
900         if (remainingBytes >= 4) { // 4, 5, 6, 7
901             return hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getInt(bytes, baseOffset));
902         }
903         return hash;
904     }
905 
906     static int hashCodeAsciiCompute(long value, int hash) {
907         // masking with 0x1f reduces the number of overall bits that impact the hash code but makes the hash
908         // code the same regardless of character case (upper case or lower case hash is the same).
909         return hash * HASH_CODE_C1 +
910                 // Low order int
911                 hashCodeAsciiSanitize((int) value) * HASH_CODE_C2 +
912                 // High order int
913                 (int) ((value & 0x1f1f1f1f00000000L) >>> 32);
914     }
915 
916     static int hashCodeAsciiSanitize(int value) {
917         return value & 0x1f1f1f1f;
918     }
919 
920     static int hashCodeAsciiSanitize(short value) {
921         return value & 0x1f1f;
922     }
923 
924     static int hashCodeAsciiSanitize(byte value) {
925         return value & 0x1f;
926     }
927 
928     static ClassLoader getClassLoader(final Class<?> clazz) {
929         if (System.getSecurityManager() == null) {
930             return clazz.getClassLoader();
931         } else {
932             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
933                 @Override
934                 public ClassLoader run() {
935                     return clazz.getClassLoader();
936                 }
937             });
938         }
939     }
940 
941     static ClassLoader getContextClassLoader() {
942         if (System.getSecurityManager() == null) {
943             return Thread.currentThread().getContextClassLoader();
944         } else {
945             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
946                 @Override
947                 public ClassLoader run() {
948                     return Thread.currentThread().getContextClassLoader();
949                 }
950             });
951         }
952     }
953 
954     static ClassLoader getSystemClassLoader() {
955         if (System.getSecurityManager() == null) {
956             return ClassLoader.getSystemClassLoader();
957         } else {
958             return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
959                 @Override
960                 public ClassLoader run() {
961                     return ClassLoader.getSystemClassLoader();
962                 }
963             });
964         }
965     }
966 
967     static int addressSize() {
968         return UNSAFE.addressSize();
969     }
970 
971     static long allocateMemory(long size) {
972         return UNSAFE.allocateMemory(size);
973     }
974 
975     static void freeMemory(long address) {
976         UNSAFE.freeMemory(address);
977     }
978 
979     static long reallocateMemory(long address, long newSize) {
980         return UNSAFE.reallocateMemory(address, newSize);
981     }
982 
983     static boolean isAndroid() {
984         return IS_ANDROID;
985     }
986 
987     private static boolean isAndroid0() {
988         // Idea: Sometimes java binaries include Android classes on the classpath, even if it isn't actually Android.
989         // Rather than check if certain classes are present, just check the VM, which is tied to the JDK.
990 
991         // Optional improvement: check if `android.os.Build.VERSION` is >= 24. On later versions of Android, the
992         // OpenJDK is used, which means `Unsafe` will actually work as expected.
993 
994         // Android sets this property to Dalvik, regardless of whether it actually is.
995         String vmName = SystemPropertyUtil.get("java.vm.name");
996         boolean isAndroid = "Dalvik".equals(vmName);
997         if (isAndroid) {
998             logger.debug("Platform: Android");
999         }
1000         return isAndroid;
1001     }
1002 
1003     private static boolean explicitTryReflectionSetAccessible0() {
1004         // we disable reflective access
1005         return SystemPropertyUtil.getBoolean("io.netty.tryReflectionSetAccessible",
1006                 javaVersion() < 9 || RUNNING_IN_NATIVE_IMAGE);
1007     }
1008 
1009     static boolean isExplicitTryReflectionSetAccessible() {
1010         return IS_EXPLICIT_TRY_REFLECTION_SET_ACCESSIBLE;
1011     }
1012 
1013     static int javaVersion() {
1014         return JAVA_VERSION;
1015     }
1016 
1017     private static int javaVersion0() {
1018         final int majorVersion;
1019 
1020         if (isAndroid0()) {
1021             majorVersion = 6;
1022         } else {
1023             majorVersion = majorVersionFromJavaSpecificationVersion();
1024         }
1025 
1026         logger.debug("Java version: {}", majorVersion);
1027 
1028         return majorVersion;
1029     }
1030 
1031     // Package-private for testing only
1032     static int majorVersionFromJavaSpecificationVersion() {
1033         return majorVersion(SystemPropertyUtil.get("java.specification.version", "1.6"));
1034     }
1035 
1036     // Package-private for testing only
1037     static int majorVersion(final String javaSpecVersion) {
1038         final String[] components = javaSpecVersion.split("\\.");
1039         final int[] version = new int[components.length];
1040         for (int i = 0; i < components.length; i++) {
1041             version[i] = Integer.parseInt(components[i]);
1042         }
1043 
1044         if (version[0] == 1) {
1045             assert version[1] >= 6;
1046             return version[1];
1047         } else {
1048             return version[0];
1049         }
1050     }
1051 
1052     private PlatformDependent0() {
1053     }
1054 }