View Javadoc
1   /*
2    * Copyright 2012 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 org.jctools.queues.MpmcArrayQueue;
21  import org.jctools.queues.MpscArrayQueue;
22  import org.jctools.queues.MpscChunkedArrayQueue;
23  import org.jctools.queues.MpscUnboundedArrayQueue;
24  import org.jctools.queues.SpscLinkedQueue;
25  import org.jctools.queues.atomic.MpmcAtomicArrayQueue;
26  import org.jctools.queues.atomic.MpscAtomicArrayQueue;
27  import org.jctools.queues.atomic.MpscChunkedAtomicArrayQueue;
28  import org.jctools.queues.atomic.MpscUnboundedAtomicArrayQueue;
29  import org.jctools.queues.atomic.SpscLinkedAtomicQueue;
30  import org.jctools.queues.atomic.unpadded.MpscAtomicUnpaddedArrayQueue;
31  import org.jctools.queues.unpadded.MpscUnpaddedArrayQueue;
32  import org.jctools.util.Pow2;
33  import org.jctools.util.UnsafeAccess;
34  
35  import java.io.File;
36  import java.io.IOException;
37  import java.lang.invoke.MethodHandle;
38  import java.lang.invoke.MethodHandles;
39  import java.lang.reflect.Field;
40  import java.nio.ByteBuffer;
41  import java.nio.ByteOrder;
42  import java.nio.charset.StandardCharsets;
43  import java.nio.file.Files;
44  import java.nio.file.Path;
45  import java.nio.file.Paths;
46  import java.security.AccessController;
47  import java.security.PrivilegedAction;
48  import java.util.Arrays;
49  import java.util.Collections;
50  import java.util.Deque;
51  import java.util.HashSet;
52  import java.util.LinkedHashSet;
53  import java.util.List;
54  import java.util.Locale;
55  import java.util.Map;
56  import java.util.Queue;
57  import java.util.Random;
58  import java.util.Set;
59  import java.util.concurrent.ConcurrentHashMap;
60  import java.util.concurrent.ConcurrentLinkedDeque;
61  import java.util.concurrent.ConcurrentMap;
62  import java.util.concurrent.ThreadLocalRandom;
63  import java.util.concurrent.atomic.AtomicLong;
64  import java.util.regex.Matcher;
65  import java.util.regex.Pattern;
66  import java.util.stream.Stream;
67  
68  import static io.netty.util.internal.PlatformDependent0.HASH_CODE_ASCII_SEED;
69  import static io.netty.util.internal.PlatformDependent0.HASH_CODE_C1;
70  import static io.netty.util.internal.PlatformDependent0.HASH_CODE_C2;
71  import static io.netty.util.internal.PlatformDependent0.hashCodeAsciiSanitize;
72  import static io.netty.util.internal.PlatformDependent0.unalignedAccess;
73  import static java.lang.Math.max;
74  import static java.lang.Math.min;
75  import static java.lang.invoke.MethodType.methodType;
76  
77  /**
78   * Utility that detects various properties specific to the current runtime
79   * environment, such as Java version and the availability of the
80   * {@code sun.misc.Unsafe} object.
81   * <p>
82   * You can disable the use of {@code sun.misc.Unsafe} if you specify
83   * the system property <strong>io.netty.noUnsafe</strong>.
84   */
85  public final class PlatformDependent {
86  
87      private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent.class);
88  
89      private static Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN;
90      private static final boolean MAYBE_SUPER_USER;
91  
92      private static final boolean CAN_ENABLE_TCP_NODELAY_BY_DEFAULT = !isAndroid();
93  
94      private static final Throwable UNSAFE_UNAVAILABILITY_CAUSE = unsafeUnavailabilityCause0();
95      private static final boolean DIRECT_BUFFER_PREFERRED;
96      private static final long MAX_DIRECT_MEMORY = estimateMaxDirectMemory();
97  
98      private static final int MPSC_CHUNK_SIZE =  1024;
99      private static final int MIN_MAX_MPSC_CAPACITY =  MPSC_CHUNK_SIZE * 2;
100     private static final int MAX_ALLOWED_MPSC_CAPACITY = Pow2.MAX_POW2;
101 
102     private static final long BYTE_ARRAY_BASE_OFFSET = byteArrayBaseOffset0();
103 
104     private static final File TMPDIR = tmpdir0();
105 
106     private static final int BIT_MODE = bitMode0();
107     private static final String NORMALIZED_ARCH = normalizeArch(SystemPropertyUtil.get("os.arch", ""));
108     private static final String NORMALIZED_OS = normalizeOs(SystemPropertyUtil.get("os.name", ""));
109 
110     // keep in sync with maven's pom.xml via os.detection.classifierWithLikes!
111     private static final String[] ALLOWED_LINUX_OS_CLASSIFIERS = {"fedora", "suse", "arch"};
112     private static final Set<String> LINUX_OS_CLASSIFIERS;
113 
114     private static final boolean IS_WINDOWS = isWindows0();
115     private static final boolean IS_OSX = isOsx0();
116     private static final boolean IS_J9_JVM = isJ9Jvm0();
117     private static final boolean IS_IVKVM_DOT_NET = isIkvmDotNet0();
118 
119     private static final int ADDRESS_SIZE = addressSize0();
120     private static final boolean USE_DIRECT_BUFFER_NO_CLEANER;
121     private static final AtomicLong DIRECT_MEMORY_COUNTER;
122     private static final long DIRECT_MEMORY_LIMIT;
123     private static final Cleaner CLEANER;
124     private static final boolean HAS_ALLOCATE_UNINIT_ARRAY;
125     // For specifications, see https://www.freedesktop.org/software/systemd/man/os-release.html
126     private static final String[] OS_RELEASE_FILES = {"/etc/os-release", "/usr/lib/os-release"};
127     private static final String LINUX_ID_PREFIX = "ID=";
128     private static final String LINUX_ID_LIKE_PREFIX = "ID_LIKE=";
129     public static final boolean BIG_ENDIAN_NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
130 
131     private static final Cleaner NOOP = new Cleaner() {
132         @Override
133         public void freeDirectBuffer(ByteBuffer buffer) {
134             // NOOP
135         }
136     };
137 
138     static {
139         // Here is how the system property is used:
140         //
141         // * <  0  - Don't use cleaner, and inherit max direct memory from java. In this case the
142         //           "practical max direct memory" would be 2 * max memory as defined by the JDK.
143         // * == 0  - Use cleaner, Netty will not enforce max memory, and instead will defer to JDK.
144         // * >  0  - Don't use cleaner. This will limit Netty's total direct memory
145         //           (note: that JDK's direct memory limit is independent of this).
146         long maxDirectMemory = SystemPropertyUtil.getLong("io.netty.maxDirectMemory", -1);
147 
148         if (maxDirectMemory == 0 || !hasUnsafe() || !PlatformDependent0.hasDirectBufferNoCleanerConstructor()) {
149             USE_DIRECT_BUFFER_NO_CLEANER = false;
150             DIRECT_MEMORY_COUNTER = null;
151         } else {
152             USE_DIRECT_BUFFER_NO_CLEANER = true;
153             if (maxDirectMemory < 0) {
154                 maxDirectMemory = MAX_DIRECT_MEMORY;
155                 if (maxDirectMemory <= 0) {
156                     DIRECT_MEMORY_COUNTER = null;
157                 } else {
158                     DIRECT_MEMORY_COUNTER = new AtomicLong();
159                 }
160             } else {
161                 DIRECT_MEMORY_COUNTER = new AtomicLong();
162             }
163         }
164         logger.debug("-Dio.netty.maxDirectMemory: {} bytes", maxDirectMemory);
165         DIRECT_MEMORY_LIMIT = maxDirectMemory >= 1 ? maxDirectMemory : MAX_DIRECT_MEMORY;
166         HAS_ALLOCATE_UNINIT_ARRAY = javaVersion() >= 9 && PlatformDependent0.hasAllocateArrayMethod();
167 
168         MAYBE_SUPER_USER = maybeSuperUser0();
169 
170         if (!isAndroid()) {
171             // only direct to method if we are not running on android.
172             // See https://github.com/netty/netty/issues/2604
173             if (javaVersion() >= 9) {
174                 CLEANER = CleanerJava9.isSupported() ? new CleanerJava9() : NOOP;
175             } else {
176                 CLEANER = CleanerJava6.isSupported() ? new CleanerJava6() : NOOP;
177             }
178         } else {
179             CLEANER = NOOP;
180         }
181 
182         // We should always prefer direct buffers by default if we can use a Cleaner to release direct buffers.
183         DIRECT_BUFFER_PREFERRED = CLEANER != NOOP
184                                   && !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect", false);
185         if (logger.isDebugEnabled()) {
186             logger.debug("-Dio.netty.noPreferDirect: {}", !DIRECT_BUFFER_PREFERRED);
187         }
188 
189         /*
190          * We do not want to log this message if unsafe is explicitly disabled. Do not remove the explicit no unsafe
191          * guard.
192          */
193         if (CLEANER == NOOP && !PlatformDependent0.isExplicitNoUnsafe()) {
194             logger.info(
195                     "Your platform does not provide complete low-level API for accessing direct buffers reliably. " +
196                     "Unless explicitly requested, heap buffer will always be preferred to avoid potential system " +
197                     "instability.");
198         }
199 
200         final Set<String> allowedClassifiers = Collections.unmodifiableSet(
201                 new HashSet<String>(Arrays.asList(ALLOWED_LINUX_OS_CLASSIFIERS)));
202         final Set<String> availableClassifiers = new LinkedHashSet<String>();
203 
204         if (!addPropertyOsClassifiers(allowedClassifiers, availableClassifiers)) {
205             addFilesystemOsClassifiers(allowedClassifiers, availableClassifiers);
206         }
207         LINUX_OS_CLASSIFIERS = Collections.unmodifiableSet(availableClassifiers);
208     }
209 
210     static void addFilesystemOsClassifiers(final Set<String> allowedClassifiers,
211                                            final Set<String> availableClassifiers) {
212         for (final String osReleaseFileName : OS_RELEASE_FILES) {
213             final Path file = Paths.get(osReleaseFileName);
214             boolean found = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
215                 @Override
216                 public Boolean run() {
217                     Pattern lineSplitPattern = Pattern.compile("[ ]+");
218                     try {
219                         if (Files.exists(file)) {
220                             try (Stream<String> lines = Files.lines(file, StandardCharsets.UTF_8)) {
221                                 lines.forEach(line -> {
222                                     if (line.startsWith(LINUX_ID_PREFIX)) {
223                                         String id = normalizeOsReleaseVariableValue(
224                                                 line.substring(LINUX_ID_PREFIX.length()));
225                                         addClassifier(allowedClassifiers, availableClassifiers, id);
226                                     } else if (line.startsWith(LINUX_ID_LIKE_PREFIX)) {
227                                         line = normalizeOsReleaseVariableValue(
228                                                 line.substring(LINUX_ID_LIKE_PREFIX.length()));
229                                         addClassifier(allowedClassifiers, availableClassifiers,
230                                                 lineSplitPattern.split(line));
231                                     }
232                                 });
233                             } catch (SecurityException e) {
234                                 logger.debug("Unable to read {}", osReleaseFileName, e);
235                             } catch (IOException e) {
236                                 logger.debug("Error while reading content of {}", osReleaseFileName, e);
237                             }
238                             // specification states we should only fall back if /etc/os-release does not exist
239                             return true;
240                         }
241                     } catch (SecurityException e) {
242                         logger.debug("Unable to check if {} exists", osReleaseFileName, e);
243                     }
244                     return false;
245                 }
246             });
247 
248             if (found) {
249                 break;
250             }
251         }
252     }
253 
254     static boolean addPropertyOsClassifiers(Set<String> allowedClassifiers, Set<String> availableClassifiers) {
255         // empty: -Dio.netty.osClassifiers (no distro specific classifiers for native libs)
256         // single ID: -Dio.netty.osClassifiers=ubuntu
257         // pair ID, ID_LIKE: -Dio.netty.osClassifiers=ubuntu,debian
258         // illegal otherwise
259         String osClassifiersPropertyName = "io.netty.osClassifiers";
260         String osClassifiers = SystemPropertyUtil.get(osClassifiersPropertyName);
261         if (osClassifiers == null) {
262             return false;
263         }
264         if (osClassifiers.isEmpty()) {
265             // let users omit classifiers with just -Dio.netty.osClassifiers
266             return true;
267         }
268         String[] classifiers = osClassifiers.split(",");
269         if (classifiers.length == 0) {
270             throw new IllegalArgumentException(
271                     osClassifiersPropertyName + " property is not empty, but contains no classifiers: "
272                             + osClassifiers);
273         }
274         // at most ID, ID_LIKE classifiers
275         if (classifiers.length > 2) {
276             throw new IllegalArgumentException(
277                     osClassifiersPropertyName + " property contains more than 2 classifiers: " + osClassifiers);
278         }
279         for (String classifier : classifiers) {
280             addClassifier(allowedClassifiers, availableClassifiers, classifier);
281         }
282         return true;
283     }
284 
285     public static long byteArrayBaseOffset() {
286         return BYTE_ARRAY_BASE_OFFSET;
287     }
288 
289     public static boolean hasDirectBufferNoCleanerConstructor() {
290         return PlatformDependent0.hasDirectBufferNoCleanerConstructor();
291     }
292 
293     public static byte[] allocateUninitializedArray(int size) {
294         return HAS_ALLOCATE_UNINIT_ARRAY ?  PlatformDependent0.allocateUninitializedArray(size) : new byte[size];
295     }
296 
297     /**
298      * Returns {@code true} if and only if the current platform is Android
299      */
300     public static boolean isAndroid() {
301         return PlatformDependent0.isAndroid();
302     }
303 
304     /**
305      * Return {@code true} if the JVM is running on Windows
306      */
307     public static boolean isWindows() {
308         return IS_WINDOWS;
309     }
310 
311     /**
312      * Return {@code true} if the JVM is running on OSX / MacOS
313      */
314     public static boolean isOsx() {
315         return IS_OSX;
316     }
317 
318     /**
319      * Return {@code true} if the current user may be a super-user. Be aware that this is just an hint and so it may
320      * return false-positives.
321      */
322     public static boolean maybeSuperUser() {
323         return MAYBE_SUPER_USER;
324     }
325 
326     /**
327      * Return the version of Java under which this library is used.
328      */
329     public static int javaVersion() {
330         return PlatformDependent0.javaVersion();
331     }
332 
333     /**
334      * Returns {@code true} if and only if it is fine to enable TCP_NODELAY socket option by default.
335      */
336     public static boolean canEnableTcpNoDelayByDefault() {
337         return CAN_ENABLE_TCP_NODELAY_BY_DEFAULT;
338     }
339 
340     /**
341      * Return {@code true} if {@code sun.misc.Unsafe} was found on the classpath and can be used for accelerated
342      * direct memory access.
343      */
344     public static boolean hasUnsafe() {
345         return UNSAFE_UNAVAILABILITY_CAUSE == null;
346     }
347 
348     /**
349      * Return the reason (if any) why {@code sun.misc.Unsafe} was not available.
350      */
351     public static Throwable getUnsafeUnavailabilityCause() {
352         return UNSAFE_UNAVAILABILITY_CAUSE;
353     }
354 
355     /**
356      * {@code true} if and only if the platform supports unaligned access.
357      *
358      * @see <a href="https://en.wikipedia.org/wiki/Segmentation_fault#Bus_error">Wikipedia on segfault</a>
359      */
360     public static boolean isUnaligned() {
361         return PlatformDependent0.isUnaligned();
362     }
363 
364     /**
365      * Returns {@code true} if the platform has reliable low-level direct buffer access API and a user has not specified
366      * {@code -Dio.netty.noPreferDirect} option.
367      */
368     public static boolean directBufferPreferred() {
369         return DIRECT_BUFFER_PREFERRED;
370     }
371 
372     /**
373      * Returns the maximum memory reserved for direct buffer allocation.
374      */
375     public static long maxDirectMemory() {
376         return DIRECT_MEMORY_LIMIT;
377     }
378 
379     /**
380      * Returns the current memory reserved for direct buffer allocation.
381      * This method returns -1 in case that a value is not available.
382      *
383      * @see #maxDirectMemory()
384      */
385     public static long usedDirectMemory() {
386         return DIRECT_MEMORY_COUNTER != null ? DIRECT_MEMORY_COUNTER.get() : -1;
387     }
388 
389     /**
390      * Returns the temporary directory.
391      */
392     public static File tmpdir() {
393         return TMPDIR;
394     }
395 
396     /**
397      * Returns the bit mode of the current VM (usually 32 or 64.)
398      */
399     public static int bitMode() {
400         return BIT_MODE;
401     }
402 
403     /**
404      * Return the address size of the OS.
405      * 4 (for 32 bits systems ) and 8 (for 64 bits systems).
406      */
407     public static int addressSize() {
408         return ADDRESS_SIZE;
409     }
410 
411     public static long allocateMemory(long size) {
412         return PlatformDependent0.allocateMemory(size);
413     }
414 
415     public static void freeMemory(long address) {
416         PlatformDependent0.freeMemory(address);
417     }
418 
419     public static long reallocateMemory(long address, long newSize) {
420         return PlatformDependent0.reallocateMemory(address, newSize);
421     }
422 
423     /**
424      * Raises an exception bypassing compiler checks for checked exceptions.
425      */
426     public static void throwException(Throwable t) {
427         PlatformDependent0.throwException(t);
428     }
429 
430     /**
431      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
432      */
433     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap() {
434         return new ConcurrentHashMap<K, V>();
435     }
436 
437     /**
438      * Creates a new fastest {@link LongCounter} implementation for the current platform.
439      */
440     public static LongCounter newLongCounter() {
441         return new LongAdderCounter();
442     }
443 
444     /**
445      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
446      */
447     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(int initialCapacity) {
448         return new ConcurrentHashMap<K, V>(initialCapacity);
449     }
450 
451     /**
452      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
453      */
454     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(int initialCapacity, float loadFactor) {
455         return new ConcurrentHashMap<K, V>(initialCapacity, loadFactor);
456     }
457 
458     /**
459      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
460      */
461     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(
462             int initialCapacity, float loadFactor, int concurrencyLevel) {
463         return new ConcurrentHashMap<K, V>(initialCapacity, loadFactor, concurrencyLevel);
464     }
465 
466     /**
467      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
468      */
469     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(Map<? extends K, ? extends V> map) {
470         return new ConcurrentHashMap<K, V>(map);
471     }
472 
473     /**
474      * Try to deallocate the specified direct {@link ByteBuffer}. Please note this method does nothing if
475      * the current platform does not support this operation or the specified buffer is not a direct buffer.
476      */
477     public static void freeDirectBuffer(ByteBuffer buffer) {
478         CLEANER.freeDirectBuffer(buffer);
479     }
480 
481     public static long directBufferAddress(ByteBuffer buffer) {
482         return PlatformDependent0.directBufferAddress(buffer);
483     }
484 
485     public static ByteBuffer directBuffer(long memoryAddress, int size) {
486         if (PlatformDependent0.hasDirectBufferNoCleanerConstructor()) {
487             return PlatformDependent0.newDirectBuffer(memoryAddress, size);
488         }
489         throw new UnsupportedOperationException(
490                 "sun.misc.Unsafe or java.nio.DirectByteBuffer.<init>(long, int) not available");
491     }
492 
493     public static Object getObject(Object object, long fieldOffset) {
494         return PlatformDependent0.getObject(object, fieldOffset);
495     }
496 
497     public static int getInt(Object object, long fieldOffset) {
498         return PlatformDependent0.getInt(object, fieldOffset);
499     }
500 
501     static void safeConstructPutInt(Object object, long fieldOffset, int value) {
502         PlatformDependent0.safeConstructPutInt(object, fieldOffset, value);
503     }
504 
505     public static int getIntVolatile(long address) {
506         return PlatformDependent0.getIntVolatile(address);
507     }
508 
509     public static void putIntOrdered(long adddress, int newValue) {
510         PlatformDependent0.putIntOrdered(adddress, newValue);
511     }
512 
513     public static byte getByte(long address) {
514         return PlatformDependent0.getByte(address);
515     }
516 
517     public static short getShort(long address) {
518         return PlatformDependent0.getShort(address);
519     }
520 
521     public static int getInt(long address) {
522         return PlatformDependent0.getInt(address);
523     }
524 
525     public static long getLong(long address) {
526         return PlatformDependent0.getLong(address);
527     }
528 
529     public static byte getByte(byte[] data, int index) {
530         return hasUnsafe() ? PlatformDependent0.getByte(data, index) : data[index];
531     }
532 
533     public static byte getByte(byte[] data, long index) {
534         return hasUnsafe() ? PlatformDependent0.getByte(data, index) : data[toIntExact(index)];
535     }
536 
537     public static short getShort(byte[] data, int index) {
538         return hasUnsafe() ? PlatformDependent0.getShort(data, index) : data[index];
539     }
540 
541     public static int getInt(byte[] data, int index) {
542         return hasUnsafe() ? PlatformDependent0.getInt(data, index) : data[index];
543     }
544 
545     public static int getInt(int[] data, long index) {
546         return hasUnsafe() ? PlatformDependent0.getInt(data, index) : data[toIntExact(index)];
547     }
548 
549     public static long getLong(byte[] data, int index) {
550         return hasUnsafe() ? PlatformDependent0.getLong(data, index) : data[index];
551     }
552 
553     public static long getLong(long[] data, long index) {
554         return hasUnsafe() ? PlatformDependent0.getLong(data, index) : data[toIntExact(index)];
555     }
556 
557     private static int toIntExact(long value) {
558         if (javaVersion() >= 8) {
559             return toIntExact8(value);
560         }
561         int result = (int) value;
562         if (result != value) {
563             throw new ArithmeticException("Cannot convert to exact int: " + value);
564         }
565         return result;
566     }
567 
568     @SuppressJava6Requirement(reason = "version checked")
569     private static int toIntExact8(long value) {
570         return Math.toIntExact(value);
571     }
572 
573     private static long getLongSafe(byte[] bytes, int offset) {
574         if (BIG_ENDIAN_NATIVE_ORDER) {
575             return (long) bytes[offset] << 56 |
576                     ((long) bytes[offset + 1] & 0xff) << 48 |
577                     ((long) bytes[offset + 2] & 0xff) << 40 |
578                     ((long) bytes[offset + 3] & 0xff) << 32 |
579                     ((long) bytes[offset + 4] & 0xff) << 24 |
580                     ((long) bytes[offset + 5] & 0xff) << 16 |
581                     ((long) bytes[offset + 6] & 0xff) <<  8 |
582                     (long) bytes[offset + 7] & 0xff;
583         }
584         return (long) bytes[offset] & 0xff |
585                 ((long) bytes[offset + 1] & 0xff) << 8 |
586                 ((long) bytes[offset + 2] & 0xff) << 16 |
587                 ((long) bytes[offset + 3] & 0xff) << 24 |
588                 ((long) bytes[offset + 4] & 0xff) << 32 |
589                 ((long) bytes[offset + 5] & 0xff) << 40 |
590                 ((long) bytes[offset + 6] & 0xff) << 48 |
591                 (long) bytes[offset + 7] << 56;
592     }
593 
594     private static int getIntSafe(byte[] bytes, int offset) {
595         if (BIG_ENDIAN_NATIVE_ORDER) {
596             return bytes[offset] << 24 |
597                     (bytes[offset + 1] & 0xff) << 16 |
598                     (bytes[offset + 2] & 0xff) << 8 |
599                     bytes[offset + 3] & 0xff;
600         }
601         return bytes[offset] & 0xff |
602                 (bytes[offset + 1] & 0xff) << 8 |
603                 (bytes[offset + 2] & 0xff) << 16 |
604                 bytes[offset + 3] << 24;
605     }
606 
607     private static short getShortSafe(byte[] bytes, int offset) {
608         if (BIG_ENDIAN_NATIVE_ORDER) {
609             return (short) (bytes[offset] << 8 | (bytes[offset + 1] & 0xff));
610         }
611         return (short) (bytes[offset] & 0xff | (bytes[offset + 1] << 8));
612     }
613 
614     /**
615      * Identical to {@link PlatformDependent0#hashCodeAsciiCompute(long, int)} but for {@link CharSequence}.
616      */
617     private static int hashCodeAsciiCompute(CharSequence value, int offset, int hash) {
618         if (BIG_ENDIAN_NATIVE_ORDER) {
619             return hash * HASH_CODE_C1 +
620                     // Low order int
621                     hashCodeAsciiSanitizeInt(value, offset + 4) * HASH_CODE_C2 +
622                     // High order int
623                     hashCodeAsciiSanitizeInt(value, offset);
624         }
625         return hash * HASH_CODE_C1 +
626                 // Low order int
627                 hashCodeAsciiSanitizeInt(value, offset) * HASH_CODE_C2 +
628                 // High order int
629                 hashCodeAsciiSanitizeInt(value, offset + 4);
630     }
631 
632     /**
633      * Identical to {@link PlatformDependent0#hashCodeAsciiSanitize(int)} but for {@link CharSequence}.
634      */
635     private static int hashCodeAsciiSanitizeInt(CharSequence value, int offset) {
636         if (BIG_ENDIAN_NATIVE_ORDER) {
637             // mimic a unsafe.getInt call on a big endian machine
638             return (value.charAt(offset + 3) & 0x1f) |
639                    (value.charAt(offset + 2) & 0x1f) << 8 |
640                    (value.charAt(offset + 1) & 0x1f) << 16 |
641                    (value.charAt(offset) & 0x1f) << 24;
642         }
643         return (value.charAt(offset + 3) & 0x1f) << 24 |
644                (value.charAt(offset + 2) & 0x1f) << 16 |
645                (value.charAt(offset + 1) & 0x1f) << 8 |
646                (value.charAt(offset) & 0x1f);
647     }
648 
649     /**
650      * Identical to {@link PlatformDependent0#hashCodeAsciiSanitize(short)} but for {@link CharSequence}.
651      */
652     private static int hashCodeAsciiSanitizeShort(CharSequence value, int offset) {
653         if (BIG_ENDIAN_NATIVE_ORDER) {
654             // mimic a unsafe.getShort call on a big endian machine
655             return (value.charAt(offset + 1) & 0x1f) |
656                     (value.charAt(offset) & 0x1f) << 8;
657         }
658         return (value.charAt(offset + 1) & 0x1f) << 8 |
659                 (value.charAt(offset) & 0x1f);
660     }
661 
662     /**
663      * Identical to {@link PlatformDependent0#hashCodeAsciiSanitize(byte)} but for {@link CharSequence}.
664      */
665     private static int hashCodeAsciiSanitizeByte(char value) {
666         return value & 0x1f;
667     }
668 
669     public static void putByte(long address, byte value) {
670         PlatformDependent0.putByte(address, value);
671     }
672 
673     public static void putShort(long address, short value) {
674         PlatformDependent0.putShort(address, value);
675     }
676 
677     public static void putInt(long address, int value) {
678         PlatformDependent0.putInt(address, value);
679     }
680 
681     public static void putLong(long address, long value) {
682         PlatformDependent0.putLong(address, value);
683     }
684 
685     public static void putByte(byte[] data, int index, byte value) {
686         PlatformDependent0.putByte(data, index, value);
687     }
688 
689     public static void putByte(Object data, long offset, byte value) {
690         PlatformDependent0.putByte(data, offset, value);
691     }
692 
693     public static void putShort(byte[] data, int index, short value) {
694         PlatformDependent0.putShort(data, index, value);
695     }
696 
697     public static void putInt(byte[] data, int index, int value) {
698         PlatformDependent0.putInt(data, index, value);
699     }
700 
701     public static void putLong(byte[] data, int index, long value) {
702         PlatformDependent0.putLong(data, index, value);
703     }
704 
705     public static void putObject(Object o, long offset, Object x) {
706         PlatformDependent0.putObject(o, offset, x);
707     }
708 
709     public static long objectFieldOffset(Field field) {
710         return PlatformDependent0.objectFieldOffset(field);
711     }
712 
713     public static void copyMemory(long srcAddr, long dstAddr, long length) {
714         PlatformDependent0.copyMemory(srcAddr, dstAddr, length);
715     }
716 
717     public static void copyMemory(byte[] src, int srcIndex, long dstAddr, long length) {
718         PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
719     }
720 
721     public static void copyMemory(byte[] src, int srcIndex, byte[] dst, int dstIndex, long length) {
722         PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex,
723                                       dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
724     }
725 
726     public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) {
727         PlatformDependent0.copyMemory(null, srcAddr, dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
728     }
729 
730     public static void setMemory(byte[] dst, int dstIndex, long bytes, byte value) {
731         PlatformDependent0.setMemory(dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, bytes, value);
732     }
733 
734     public static void setMemory(long address, long bytes, byte value) {
735         PlatformDependent0.setMemory(address, bytes, value);
736     }
737 
738     /**
739      * Allocate a new {@link ByteBuffer} with the given {@code capacity}. {@link ByteBuffer}s allocated with
740      * this method <strong>MUST</strong> be deallocated via {@link #freeDirectNoCleaner(ByteBuffer)}.
741      */
742     public static ByteBuffer allocateDirectNoCleaner(int capacity) {
743         assert USE_DIRECT_BUFFER_NO_CLEANER;
744 
745         incrementMemoryCounter(capacity);
746         try {
747             return PlatformDependent0.allocateDirectNoCleaner(capacity);
748         } catch (Throwable e) {
749             decrementMemoryCounter(capacity);
750             throwException(e);
751             return null;
752         }
753     }
754 
755     /**
756      * Reallocate a new {@link ByteBuffer} with the given {@code capacity}. {@link ByteBuffer}s reallocated with
757      * this method <strong>MUST</strong> be deallocated via {@link #freeDirectNoCleaner(ByteBuffer)}.
758      */
759     public static ByteBuffer reallocateDirectNoCleaner(ByteBuffer buffer, int capacity) {
760         assert USE_DIRECT_BUFFER_NO_CLEANER;
761 
762         int len = capacity - buffer.capacity();
763         incrementMemoryCounter(len);
764         try {
765             return PlatformDependent0.reallocateDirectNoCleaner(buffer, capacity);
766         } catch (Throwable e) {
767             decrementMemoryCounter(len);
768             throwException(e);
769             return null;
770         }
771     }
772 
773     /**
774      * This method <strong>MUST</strong> only be called for {@link ByteBuffer}s that were allocated via
775      * {@link #allocateDirectNoCleaner(int)}.
776      */
777     public static void freeDirectNoCleaner(ByteBuffer buffer) {
778         assert USE_DIRECT_BUFFER_NO_CLEANER;
779 
780         int capacity = buffer.capacity();
781         PlatformDependent0.freeMemory(PlatformDependent0.directBufferAddress(buffer));
782         decrementMemoryCounter(capacity);
783     }
784 
785     public static boolean hasAlignDirectByteBuffer() {
786         return hasUnsafe() || PlatformDependent0.hasAlignSliceMethod();
787     }
788 
789     public static ByteBuffer alignDirectBuffer(ByteBuffer buffer, int alignment) {
790         if (!buffer.isDirect()) {
791             throw new IllegalArgumentException("Cannot get aligned slice of non-direct byte buffer.");
792         }
793         if (PlatformDependent0.hasAlignSliceMethod()) {
794             return PlatformDependent0.alignSlice(buffer, alignment);
795         }
796         if (hasUnsafe()) {
797             long address = directBufferAddress(buffer);
798             long aligned = align(address, alignment);
799             buffer.position((int) (aligned - address));
800             return buffer.slice();
801         }
802         // We don't have enough information to be able to align any buffers.
803         throw new UnsupportedOperationException("Cannot align direct buffer. " +
804                 "Needs either Unsafe or ByteBuffer.alignSlice method available.");
805     }
806 
807     public static long align(long value, int alignment) {
808         return Pow2.align(value, alignment);
809     }
810 
811     private static void incrementMemoryCounter(int capacity) {
812         if (DIRECT_MEMORY_COUNTER != null) {
813             long newUsedMemory = DIRECT_MEMORY_COUNTER.addAndGet(capacity);
814             if (newUsedMemory > DIRECT_MEMORY_LIMIT) {
815                 DIRECT_MEMORY_COUNTER.addAndGet(-capacity);
816                 throw new OutOfDirectMemoryError("failed to allocate " + capacity
817                         + " byte(s) of direct memory (used: " + (newUsedMemory - capacity)
818                         + ", max: " + DIRECT_MEMORY_LIMIT + ')');
819             }
820         }
821     }
822 
823     private static void decrementMemoryCounter(int capacity) {
824         if (DIRECT_MEMORY_COUNTER != null) {
825             long usedMemory = DIRECT_MEMORY_COUNTER.addAndGet(-capacity);
826             assert usedMemory >= 0;
827         }
828     }
829 
830     public static boolean useDirectBufferNoCleaner() {
831         return USE_DIRECT_BUFFER_NO_CLEANER;
832     }
833 
834     /**
835      * Compare two {@code byte} arrays for equality. For performance reasons no bounds checking on the
836      * parameters is performed.
837      *
838      * @param bytes1 the first byte array.
839      * @param startPos1 the position (inclusive) to start comparing in {@code bytes1}.
840      * @param bytes2 the second byte array.
841      * @param startPos2 the position (inclusive) to start comparing in {@code bytes2}.
842      * @param length the amount of bytes to compare. This is assumed to be validated as not going out of bounds
843      * by the caller.
844      */
845     public static boolean equals(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
846         if (javaVersion() > 8 && (startPos2 | startPos1 | (bytes1.length - length) | bytes2.length - length) == 0) {
847             return Arrays.equals(bytes1, bytes2);
848         }
849         return !hasUnsafe() || !unalignedAccess() ?
850                   equalsSafe(bytes1, startPos1, bytes2, startPos2, length) :
851                   PlatformDependent0.equals(bytes1, startPos1, bytes2, startPos2, length);
852     }
853 
854     /**
855      * Determine if a subsection of an array is zero.
856      * @param bytes The byte array.
857      * @param startPos The starting index (inclusive) in {@code bytes}.
858      * @param length The amount of bytes to check for zero.
859      * @return {@code false} if {@code bytes[startPos:startsPos+length)} contains a value other than zero.
860      */
861     public static boolean isZero(byte[] bytes, int startPos, int length) {
862         return !hasUnsafe() || !unalignedAccess() ?
863                 isZeroSafe(bytes, startPos, length) :
864                 PlatformDependent0.isZero(bytes, startPos, length);
865     }
866 
867     /**
868      * Compare two {@code byte} arrays for equality without leaking timing information.
869      * For performance reasons no bounds checking on the parameters is performed.
870      * <p>
871      * The {@code int} return type is intentional and is designed to allow cascading of constant time operations:
872      * <pre>
873      *     byte[] s1 = new {1, 2, 3};
874      *     byte[] s2 = new {1, 2, 3};
875      *     byte[] s3 = new {1, 2, 3};
876      *     byte[] s4 = new {4, 5, 6};
877      *     boolean equals = (equalsConstantTime(s1, 0, s2, 0, s1.length) &
878      *                       equalsConstantTime(s3, 0, s4, 0, s3.length)) != 0;
879      * </pre>
880      * @param bytes1 the first byte array.
881      * @param startPos1 the position (inclusive) to start comparing in {@code bytes1}.
882      * @param bytes2 the second byte array.
883      * @param startPos2 the position (inclusive) to start comparing in {@code bytes2}.
884      * @param length the amount of bytes to compare. This is assumed to be validated as not going out of bounds
885      * by the caller.
886      * @return {@code 0} if not equal. {@code 1} if equal.
887      */
888     public static int equalsConstantTime(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
889         return !hasUnsafe() || !unalignedAccess() ?
890                   ConstantTimeUtils.equalsConstantTime(bytes1, startPos1, bytes2, startPos2, length) :
891                   PlatformDependent0.equalsConstantTime(bytes1, startPos1, bytes2, startPos2, length);
892     }
893 
894     /**
895      * Calculate a hash code of a byte array assuming ASCII character encoding.
896      * The resulting hash code will be case insensitive.
897      * @param bytes The array which contains the data to hash.
898      * @param startPos What index to start generating a hash code in {@code bytes}
899      * @param length The amount of bytes that should be accounted for in the computation.
900      * @return The hash code of {@code bytes} assuming ASCII character encoding.
901      * The resulting hash code will be case insensitive.
902      */
903     public static int hashCodeAscii(byte[] bytes, int startPos, int length) {
904         return !hasUnsafe() || !unalignedAccess() ?
905                 hashCodeAsciiSafe(bytes, startPos, length) :
906                 PlatformDependent0.hashCodeAscii(bytes, startPos, length);
907     }
908 
909     /**
910      * Calculate a hash code of a byte array assuming ASCII character encoding.
911      * The resulting hash code will be case insensitive.
912      * <p>
913      * This method assumes that {@code bytes} is equivalent to a {@code byte[]} but just using {@link CharSequence}
914      * for storage. The upper most byte of each {@code char} from {@code bytes} is ignored.
915      * @param bytes The array which contains the data to hash (assumed to be equivalent to a {@code byte[]}).
916      * @return The hash code of {@code bytes} assuming ASCII character encoding.
917      * The resulting hash code will be case insensitive.
918      */
919     public static int hashCodeAscii(CharSequence bytes) {
920         final int length = bytes.length();
921         final int remainingBytes = length & 7;
922         int hash = HASH_CODE_ASCII_SEED;
923         // Benchmarking shows that by just naively looping for inputs 8~31 bytes long we incur a relatively large
924         // performance penalty (only achieve about 60% performance of loop which iterates over each char). So because
925         // of this we take special provisions to unroll the looping for these conditions.
926         if (length >= 32) {
927             for (int i = length - 8; i >= remainingBytes; i -= 8) {
928                 hash = hashCodeAsciiCompute(bytes, i, hash);
929             }
930         } else if (length >= 8) {
931             hash = hashCodeAsciiCompute(bytes, length - 8, hash);
932             if (length >= 16) {
933                 hash = hashCodeAsciiCompute(bytes, length - 16, hash);
934                 if (length >= 24) {
935                     hash = hashCodeAsciiCompute(bytes, length - 24, hash);
936                 }
937             }
938         }
939         if (remainingBytes == 0) {
940             return hash;
941         }
942         int offset = 0;
943         if (remainingBytes != 2 & remainingBytes != 4 & remainingBytes != 6) { // 1, 3, 5, 7
944             hash = hash * HASH_CODE_C1 + hashCodeAsciiSanitizeByte(bytes.charAt(0));
945             offset = 1;
946         }
947         if (remainingBytes != 1 & remainingBytes != 4 & remainingBytes != 5) { // 2, 3, 6, 7
948             hash = hash * (offset == 0 ? HASH_CODE_C1 : HASH_CODE_C2)
949                     + hashCodeAsciiSanitize(hashCodeAsciiSanitizeShort(bytes, offset));
950             offset += 2;
951         }
952         if (remainingBytes >= 4) { // 4, 5, 6, 7
953             return hash * ((offset == 0 | offset == 3) ? HASH_CODE_C1 : HASH_CODE_C2)
954                     + hashCodeAsciiSanitizeInt(bytes, offset);
955         }
956         return hash;
957     }
958 
959     private static final class Mpsc {
960         private static final boolean USE_MPSC_CHUNKED_ARRAY_QUEUE;
961 
962         private Mpsc() {
963         }
964 
965         static {
966             Object unsafe = null;
967             if (hasUnsafe()) {
968                 // jctools goes through its own process of initializing unsafe; of
969                 // course, this requires permissions which might not be granted to calling code, so we
970                 // must mark this block as privileged too
971                 unsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
972                     @Override
973                     public Object run() {
974                         // force JCTools to initialize unsafe
975                         return UnsafeAccess.UNSAFE;
976                     }
977                 });
978             }
979 
980             if (unsafe == null) {
981                 logger.debug("org.jctools-core.MpscChunkedArrayQueue: unavailable");
982                 USE_MPSC_CHUNKED_ARRAY_QUEUE = false;
983             } else {
984                 logger.debug("org.jctools-core.MpscChunkedArrayQueue: available");
985                 USE_MPSC_CHUNKED_ARRAY_QUEUE = true;
986             }
987         }
988 
989         static <T> Queue<T> newMpscQueue(final int maxCapacity) {
990             // Calculate the max capacity which can not be bigger than MAX_ALLOWED_MPSC_CAPACITY.
991             // This is forced by the MpscChunkedArrayQueue implementation as will try to round it
992             // up to the next power of two and so will overflow otherwise.
993             final int capacity = max(min(maxCapacity, MAX_ALLOWED_MPSC_CAPACITY), MIN_MAX_MPSC_CAPACITY);
994             return newChunkedMpscQueue(MPSC_CHUNK_SIZE, capacity);
995         }
996 
997         static <T> Queue<T> newChunkedMpscQueue(final int chunkSize, final int capacity) {
998             return USE_MPSC_CHUNKED_ARRAY_QUEUE ? new MpscChunkedArrayQueue<T>(chunkSize, capacity)
999                     : new MpscChunkedAtomicArrayQueue<T>(chunkSize, capacity);
1000         }
1001 
1002         static <T> Queue<T> newMpscQueue() {
1003             return USE_MPSC_CHUNKED_ARRAY_QUEUE ? new MpscUnboundedArrayQueue<T>(MPSC_CHUNK_SIZE)
1004                                                 : new MpscUnboundedAtomicArrayQueue<T>(MPSC_CHUNK_SIZE);
1005         }
1006     }
1007 
1008     /**
1009      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
1010      * consumer (one thread!).
1011      * @return A MPSC queue which may be unbounded.
1012      */
1013     public static <T> Queue<T> newMpscQueue() {
1014         return Mpsc.newMpscQueue();
1015     }
1016 
1017     /**
1018      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
1019      * consumer (one thread!).
1020      */
1021     public static <T> Queue<T> newMpscQueue(final int maxCapacity) {
1022         return Mpsc.newMpscQueue(maxCapacity);
1023     }
1024 
1025     /**
1026      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
1027      * consumer (one thread!).
1028      * The queue will grow and shrink its capacity in units of the given chunk size.
1029      */
1030     public static <T> Queue<T> newMpscQueue(final int chunkSize, final int maxCapacity) {
1031         return Mpsc.newChunkedMpscQueue(chunkSize, maxCapacity);
1032     }
1033 
1034     /**
1035      * Create a new {@link Queue} which is safe to use for single producer (one thread!) and a single
1036      * consumer (one thread!).
1037      */
1038     public static <T> Queue<T> newSpscQueue() {
1039         return hasUnsafe() ? new SpscLinkedQueue<T>() : new SpscLinkedAtomicQueue<T>();
1040     }
1041 
1042     /**
1043      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
1044      * consumer (one thread!) with the given fixes {@code capacity}.
1045      */
1046     public static <T> Queue<T> newFixedMpscQueue(int capacity) {
1047         return hasUnsafe() ? new MpscArrayQueue<T>(capacity) : new MpscAtomicArrayQueue<T>(capacity);
1048     }
1049 
1050     /**
1051      * Create a new un-padded {@link Queue} which is safe to use for multiple producers (different threads) and a single
1052      * consumer (one thread!) with the given fixes {@code capacity}.<br>
1053      * This should be preferred to {@link #newFixedMpscQueue(int)} when the queue is not to be heavily contended.
1054      */
1055     public static <T> Queue<T> newFixedMpscUnpaddedQueue(int capacity) {
1056         return hasUnsafe() ? new MpscUnpaddedArrayQueue<T>(capacity) : new MpscAtomicUnpaddedArrayQueue<T>(capacity);
1057     }
1058 
1059     /**
1060      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and multiple
1061      * consumers with the given fixes {@code capacity}.
1062      */
1063     public static <T> Queue<T> newFixedMpmcQueue(int capacity) {
1064         return hasUnsafe() ? new MpmcArrayQueue<T>(capacity) : new MpmcAtomicArrayQueue<T>(capacity);
1065     }
1066 
1067     /**
1068      * Return the {@link ClassLoader} for the given {@link Class}.
1069      */
1070     public static ClassLoader getClassLoader(final Class<?> clazz) {
1071         return PlatformDependent0.getClassLoader(clazz);
1072     }
1073 
1074     /**
1075      * Return the context {@link ClassLoader} for the current {@link Thread}.
1076      */
1077     public static ClassLoader getContextClassLoader() {
1078         return PlatformDependent0.getContextClassLoader();
1079     }
1080 
1081     /**
1082      * Return the system {@link ClassLoader}.
1083      */
1084     public static ClassLoader getSystemClassLoader() {
1085         return PlatformDependent0.getSystemClassLoader();
1086     }
1087 
1088     /**
1089      * Returns a new concurrent {@link Deque}.
1090      */
1091     public static <C> Deque<C> newConcurrentDeque() {
1092         return new ConcurrentLinkedDeque<C>();
1093     }
1094 
1095     /**
1096      * Return a {@link Random} which is not-threadsafe and so can only be used from the same thread.
1097      */
1098     public static Random threadLocalRandom() {
1099         return ThreadLocalRandom.current();
1100     }
1101 
1102     private static boolean isWindows0() {
1103         boolean windows = "windows".equals(NORMALIZED_OS);
1104         if (windows) {
1105             logger.debug("Platform: Windows");
1106         }
1107         return windows;
1108     }
1109 
1110     private static boolean isOsx0() {
1111         boolean osx = "osx".equals(NORMALIZED_OS);
1112         if (osx) {
1113             logger.debug("Platform: MacOS");
1114         }
1115         return osx;
1116     }
1117 
1118     private static boolean maybeSuperUser0() {
1119         String username = SystemPropertyUtil.get("user.name");
1120         if (isWindows()) {
1121             return "Administrator".equals(username);
1122         }
1123         // Check for root and toor as some BSDs have a toor user that is basically the same as root.
1124         return "root".equals(username) || "toor".equals(username);
1125     }
1126 
1127     private static Throwable unsafeUnavailabilityCause0() {
1128         if (isAndroid()) {
1129             logger.debug("sun.misc.Unsafe: unavailable (Android)");
1130             return new UnsupportedOperationException("sun.misc.Unsafe: unavailable (Android)");
1131         }
1132 
1133         if (isIkvmDotNet()) {
1134             logger.debug("sun.misc.Unsafe: unavailable (IKVM.NET)");
1135             return new UnsupportedOperationException("sun.misc.Unsafe: unavailable (IKVM.NET)");
1136         }
1137 
1138         Throwable cause = PlatformDependent0.getUnsafeUnavailabilityCause();
1139         if (cause != null) {
1140             return cause;
1141         }
1142 
1143         try {
1144             boolean hasUnsafe = PlatformDependent0.hasUnsafe();
1145             logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable");
1146             return hasUnsafe ? null : PlatformDependent0.getUnsafeUnavailabilityCause();
1147         } catch (Throwable t) {
1148             logger.trace("Could not determine if Unsafe is available", t);
1149             // Probably failed to initialize PlatformDependent0.
1150             return new UnsupportedOperationException("Could not determine if Unsafe is available", t);
1151         }
1152     }
1153 
1154     /**
1155      * Returns {@code true} if the running JVM is either <a href="https://developer.ibm.com/javasdk/">IBM J9</a> or
1156      * <a href="https://www.eclipse.org/openj9/">Eclipse OpenJ9</a>, {@code false} otherwise.
1157      */
1158     public static boolean isJ9Jvm() {
1159         return IS_J9_JVM;
1160     }
1161 
1162     private static boolean isJ9Jvm0() {
1163         String vmName = SystemPropertyUtil.get("java.vm.name", "").toLowerCase();
1164         return vmName.startsWith("ibm j9") || vmName.startsWith("eclipse openj9");
1165     }
1166 
1167     /**
1168      * Returns {@code true} if the running JVM is <a href="https://www.ikvm.net">IKVM.NET</a>, {@code false} otherwise.
1169      */
1170     public static boolean isIkvmDotNet() {
1171         return IS_IVKVM_DOT_NET;
1172     }
1173 
1174     private static boolean isIkvmDotNet0() {
1175         String vmName = SystemPropertyUtil.get("java.vm.name", "").toUpperCase(Locale.US);
1176         return vmName.equals("IKVM.NET");
1177     }
1178 
1179     private static Pattern getMaxDirectMemorySizeArgPattern() {
1180         // Pattern's is immutable so it's always safe published
1181         Pattern pattern = MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN;
1182         if (pattern == null) {
1183             pattern = Pattern.compile("\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$");
1184             MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN =  pattern;
1185         }
1186         return pattern;
1187     }
1188 
1189     /**
1190      * Compute an estimate of the maximum amount of direct memory available to this JVM.
1191      * <p>
1192      * The computation is not cached, so you probably want to use {@link #maxDirectMemory()} instead.
1193      * <p>
1194      * This will produce debug log output when called.
1195      *
1196      * @return The estimated max direct memory, in bytes.
1197      */
1198     @SuppressWarnings("unchecked")
1199     public static long estimateMaxDirectMemory() {
1200         long maxDirectMemory = PlatformDependent0.bitsMaxDirectMemory();
1201         if (maxDirectMemory > 0) {
1202             return maxDirectMemory;
1203         }
1204 
1205         try {
1206             // Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it.
1207             // Note that we are using reflection because Android doesn't have these classes.
1208             ClassLoader systemClassLoader = getSystemClassLoader();
1209             Class<?> mgmtFactoryClass = Class.forName(
1210                     "java.lang.management.ManagementFactory", true, systemClassLoader);
1211             Class<?> runtimeClass = Class.forName(
1212                     "java.lang.management.RuntimeMXBean", true, systemClassLoader);
1213 
1214             MethodHandles.Lookup lookup = MethodHandles.publicLookup();
1215             MethodHandle getRuntime = lookup.findStatic(
1216                     mgmtFactoryClass, "getRuntimeMXBean", methodType(runtimeClass));
1217             MethodHandle getInputArguments = lookup.findVirtual(
1218                     runtimeClass, "getInputArguments", methodType(List.class));
1219             List<String> vmArgs = (List<String>) getInputArguments.invoke(getRuntime.invoke());
1220 
1221             Pattern maxDirectMemorySizeArgPattern = getMaxDirectMemorySizeArgPattern();
1222 
1223             for (int i = vmArgs.size() - 1; i >= 0; i --) {
1224                 Matcher m = maxDirectMemorySizeArgPattern.matcher(vmArgs.get(i));
1225                 if (!m.matches()) {
1226                     continue;
1227                 }
1228 
1229                 maxDirectMemory = Long.parseLong(m.group(1));
1230                 switch (m.group(2).charAt(0)) {
1231                     case 'k': case 'K':
1232                         maxDirectMemory *= 1024;
1233                         break;
1234                     case 'm': case 'M':
1235                         maxDirectMemory *= 1024 * 1024;
1236                         break;
1237                     case 'g': case 'G':
1238                         maxDirectMemory *= 1024 * 1024 * 1024;
1239                         break;
1240                     default:
1241                         break;
1242                 }
1243                 break;
1244             }
1245         } catch (Throwable ignored) {
1246             // Ignore
1247         }
1248 
1249         if (maxDirectMemory <= 0) {
1250             maxDirectMemory = Runtime.getRuntime().maxMemory();
1251             logger.debug("maxDirectMemory: {} bytes (maybe)", maxDirectMemory);
1252         } else {
1253             logger.debug("maxDirectMemory: {} bytes", maxDirectMemory);
1254         }
1255 
1256         return maxDirectMemory;
1257     }
1258 
1259     private static File tmpdir0() {
1260         File f;
1261         try {
1262             f = toDirectory(SystemPropertyUtil.get("io.netty.tmpdir"));
1263             if (f != null) {
1264                 logger.debug("-Dio.netty.tmpdir: {}", f);
1265                 return f;
1266             }
1267 
1268             f = toDirectory(SystemPropertyUtil.get("java.io.tmpdir"));
1269             if (f != null) {
1270                 logger.debug("-Dio.netty.tmpdir: {} (java.io.tmpdir)", f);
1271                 return f;
1272             }
1273 
1274             // This shouldn't happen, but just in case ..
1275             if (isWindows()) {
1276                 f = toDirectory(System.getenv("TEMP"));
1277                 if (f != null) {
1278                     logger.debug("-Dio.netty.tmpdir: {} (%TEMP%)", f);
1279                     return f;
1280                 }
1281 
1282                 String userprofile = System.getenv("USERPROFILE");
1283                 if (userprofile != null) {
1284                     f = toDirectory(userprofile + "\\AppData\\Local\\Temp");
1285                     if (f != null) {
1286                         logger.debug("-Dio.netty.tmpdir: {} (%USERPROFILE%\\AppData\\Local\\Temp)", f);
1287                         return f;
1288                     }
1289 
1290                     f = toDirectory(userprofile + "\\Local Settings\\Temp");
1291                     if (f != null) {
1292                         logger.debug("-Dio.netty.tmpdir: {} (%USERPROFILE%\\Local Settings\\Temp)", f);
1293                         return f;
1294                     }
1295                 }
1296             } else {
1297                 f = toDirectory(System.getenv("TMPDIR"));
1298                 if (f != null) {
1299                     logger.debug("-Dio.netty.tmpdir: {} ($TMPDIR)", f);
1300                     return f;
1301                 }
1302             }
1303         } catch (Throwable ignored) {
1304             // Environment variable inaccessible
1305         }
1306 
1307         // Last resort.
1308         if (isWindows()) {
1309             f = new File("C:\\Windows\\Temp");
1310         } else {
1311             f = new File("/tmp");
1312         }
1313 
1314         logger.warn("Failed to get the temporary directory; falling back to: {}", f);
1315         return f;
1316     }
1317 
1318     @SuppressWarnings("ResultOfMethodCallIgnored")
1319     private static File toDirectory(String path) {
1320         if (path == null) {
1321             return null;
1322         }
1323 
1324         File f = new File(path);
1325         f.mkdirs();
1326 
1327         if (!f.isDirectory()) {
1328             return null;
1329         }
1330 
1331         try {
1332             return f.getAbsoluteFile();
1333         } catch (Exception ignored) {
1334             return f;
1335         }
1336     }
1337 
1338     private static int bitMode0() {
1339         // Check user-specified bit mode first.
1340         int bitMode = SystemPropertyUtil.getInt("io.netty.bitMode", 0);
1341         if (bitMode > 0) {
1342             logger.debug("-Dio.netty.bitMode: {}", bitMode);
1343             return bitMode;
1344         }
1345 
1346         // And then the vendor specific ones which is probably most reliable.
1347         bitMode = SystemPropertyUtil.getInt("sun.arch.data.model", 0);
1348         if (bitMode > 0) {
1349             logger.debug("-Dio.netty.bitMode: {} (sun.arch.data.model)", bitMode);
1350             return bitMode;
1351         }
1352         bitMode = SystemPropertyUtil.getInt("com.ibm.vm.bitmode", 0);
1353         if (bitMode > 0) {
1354             logger.debug("-Dio.netty.bitMode: {} (com.ibm.vm.bitmode)", bitMode);
1355             return bitMode;
1356         }
1357 
1358         // os.arch also gives us a good hint.
1359         String arch = SystemPropertyUtil.get("os.arch", "").toLowerCase(Locale.US).trim();
1360         if ("amd64".equals(arch) || "x86_64".equals(arch)) {
1361             bitMode = 64;
1362         } else if ("i386".equals(arch) || "i486".equals(arch) || "i586".equals(arch) || "i686".equals(arch)) {
1363             bitMode = 32;
1364         }
1365 
1366         if (bitMode > 0) {
1367             logger.debug("-Dio.netty.bitMode: {} (os.arch: {})", bitMode, arch);
1368         }
1369 
1370         // Last resort: guess from VM name and then fall back to most common 64-bit mode.
1371         String vm = SystemPropertyUtil.get("java.vm.name", "").toLowerCase(Locale.US);
1372         Pattern bitPattern = Pattern.compile("([1-9][0-9]+)-?bit");
1373         Matcher m = bitPattern.matcher(vm);
1374         if (m.find()) {
1375             return Integer.parseInt(m.group(1));
1376         } else {
1377             return 64;
1378         }
1379     }
1380 
1381     private static int addressSize0() {
1382         if (!hasUnsafe()) {
1383             return -1;
1384         }
1385         return PlatformDependent0.addressSize();
1386     }
1387 
1388     private static long byteArrayBaseOffset0() {
1389         if (!hasUnsafe()) {
1390             return -1;
1391         }
1392         return PlatformDependent0.byteArrayBaseOffset();
1393     }
1394 
1395     private static boolean equalsSafe(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
1396         final int end = startPos1 + length;
1397         for (; startPos1 < end; ++startPos1, ++startPos2) {
1398             if (bytes1[startPos1] != bytes2[startPos2]) {
1399                 return false;
1400             }
1401         }
1402         return true;
1403     }
1404 
1405     private static boolean isZeroSafe(byte[] bytes, int startPos, int length) {
1406         final int end = startPos + length;
1407         for (; startPos < end; ++startPos) {
1408             if (bytes[startPos] != 0) {
1409                 return false;
1410             }
1411         }
1412         return true;
1413     }
1414 
1415     /**
1416      * Package private for testing purposes only!
1417      */
1418     static int hashCodeAsciiSafe(byte[] bytes, int startPos, int length) {
1419         int hash = HASH_CODE_ASCII_SEED;
1420         final int remainingBytes = length & 7;
1421         final int end = startPos + remainingBytes;
1422         for (int i = startPos - 8 + length; i >= end; i -= 8) {
1423             hash = PlatformDependent0.hashCodeAsciiCompute(getLongSafe(bytes, i), hash);
1424         }
1425         switch(remainingBytes) {
1426         case 7:
1427             return ((hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]))
1428                           * HASH_CODE_C2 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos + 1)))
1429                           * HASH_CODE_C1 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos + 3));
1430         case 6:
1431             return (hash * HASH_CODE_C1 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos)))
1432                          * HASH_CODE_C2 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos + 2));
1433         case 5:
1434             return (hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]))
1435                          * HASH_CODE_C2 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos + 1));
1436         case 4:
1437             return hash * HASH_CODE_C1 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos));
1438         case 3:
1439             return (hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]))
1440                          * HASH_CODE_C2 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos + 1));
1441         case 2:
1442             return hash * HASH_CODE_C1 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos));
1443         case 1:
1444             return hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]);
1445         default:
1446             return hash;
1447         }
1448     }
1449 
1450     public static String normalizedArch() {
1451         return NORMALIZED_ARCH;
1452     }
1453 
1454     public static String normalizedOs() {
1455         return NORMALIZED_OS;
1456     }
1457 
1458     public static Set<String> normalizedLinuxClassifiers() {
1459         return LINUX_OS_CLASSIFIERS;
1460     }
1461 
1462     public static File createTempFile(String prefix, String suffix, File directory) throws IOException {
1463         if (directory == null) {
1464             return Files.createTempFile(prefix, suffix).toFile();
1465         }
1466         return Files.createTempFile(directory.toPath(), prefix, suffix).toFile();
1467     }
1468 
1469     /**
1470      * Adds only those classifier strings to <tt>dest</tt> which are present in <tt>allowed</tt>.
1471      *
1472      * @param allowed          allowed classifiers
1473      * @param dest             destination set
1474      * @param maybeClassifiers potential classifiers to add
1475      */
1476     private static void addClassifier(Set<String> allowed, Set<String> dest, String... maybeClassifiers) {
1477         for (String id : maybeClassifiers) {
1478             if (allowed.contains(id)) {
1479                 dest.add(id);
1480             }
1481         }
1482     }
1483 
1484     private static String normalizeOsReleaseVariableValue(String value) {
1485         // Variable assignment values may be enclosed in double or single quotes.
1486         return value.trim().replaceAll("[\"']", "");
1487     }
1488 
1489     private static String normalize(String value) {
1490         return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+", "");
1491     }
1492 
1493     private static String normalizeArch(String value) {
1494         value = normalize(value);
1495         if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
1496             return "x86_64";
1497         }
1498         if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
1499             return "x86_32";
1500         }
1501         if (value.matches("^(ia64|itanium64)$")) {
1502             return "itanium_64";
1503         }
1504         if (value.matches("^(sparc|sparc32)$")) {
1505             return "sparc_32";
1506         }
1507         if (value.matches("^(sparcv9|sparc64)$")) {
1508             return "sparc_64";
1509         }
1510         if (value.matches("^(arm|arm32)$")) {
1511             return "arm_32";
1512         }
1513         if ("aarch64".equals(value)) {
1514             return "aarch_64";
1515         }
1516         if ("riscv64".equals(value)) {
1517             // os.detected.arch is riscv64 for RISC-V, no underscore
1518             return "riscv64";
1519         }
1520         if (value.matches("^(ppc|ppc32)$")) {
1521             return "ppc_32";
1522         }
1523         if ("ppc64".equals(value)) {
1524             return "ppc_64";
1525         }
1526         if ("ppc64le".equals(value)) {
1527             return "ppcle_64";
1528         }
1529         if ("s390".equals(value)) {
1530             return "s390_32";
1531         }
1532         if ("s390x".equals(value)) {
1533             return "s390_64";
1534         }
1535         if ("loongarch64".equals(value)) {
1536             return "loongarch_64";
1537         }
1538 
1539         return "unknown";
1540     }
1541 
1542     private static String normalizeOs(String value) {
1543         value = normalize(value);
1544         if (value.startsWith("aix")) {
1545             return "aix";
1546         }
1547         if (value.startsWith("hpux")) {
1548             return "hpux";
1549         }
1550         if (value.startsWith("os400")) {
1551             // Avoid the names such as os4000
1552             if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) {
1553                 return "os400";
1554             }
1555         }
1556         if (value.startsWith("linux")) {
1557             return "linux";
1558         }
1559         if (value.startsWith("macosx") || value.startsWith("osx") || value.startsWith("darwin")) {
1560             return "osx";
1561         }
1562         if (value.startsWith("freebsd")) {
1563             return "freebsd";
1564         }
1565         if (value.startsWith("openbsd")) {
1566             return "openbsd";
1567         }
1568         if (value.startsWith("netbsd")) {
1569             return "netbsd";
1570         }
1571         if (value.startsWith("solaris") || value.startsWith("sunos")) {
1572             return "sunos";
1573         }
1574         if (value.startsWith("windows")) {
1575             return "windows";
1576         }
1577 
1578         return "unknown";
1579     }
1580 
1581     private static final class AtomicLongCounter extends AtomicLong implements LongCounter {
1582         private static final long serialVersionUID = 4074772784610639305L;
1583 
1584         @Override
1585         public void add(long delta) {
1586             addAndGet(delta);
1587         }
1588 
1589         @Override
1590         public void increment() {
1591             incrementAndGet();
1592         }
1593 
1594         @Override
1595         public void decrement() {
1596             decrementAndGet();
1597         }
1598 
1599         @Override
1600         public long value() {
1601             return get();
1602         }
1603     }
1604 
1605     private interface ThreadLocalRandomProvider {
1606         Random current();
1607     }
1608 
1609     private PlatformDependent() {
1610         // only static method supported
1611     }
1612 }