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  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations
14  * under the License.
15  */

16 package io.netty.util.internal;
17
18 import io.netty.util.CharsetUtil;
19 import io.netty.util.internal.logging.InternalLogger;
20 import io.netty.util.internal.logging.InternalLoggerFactory;
21 import io.netty.util.internal.shaded.org.jctools.queues.MpscArrayQueue;
22 import io.netty.util.internal.shaded.org.jctools.queues.MpscChunkedArrayQueue;
23 import io.netty.util.internal.shaded.org.jctools.queues.MpscUnboundedArrayQueue;
24 import io.netty.util.internal.shaded.org.jctools.queues.SpscLinkedQueue;
25 import io.netty.util.internal.shaded.org.jctools.queues.atomic.MpscAtomicArrayQueue;
26 import io.netty.util.internal.shaded.org.jctools.queues.atomic.MpscChunkedAtomicArrayQueue;
27 import io.netty.util.internal.shaded.org.jctools.queues.atomic.MpscUnboundedAtomicArrayQueue;
28 import io.netty.util.internal.shaded.org.jctools.queues.atomic.SpscLinkedAtomicQueue;
29 import io.netty.util.internal.shaded.org.jctools.util.Pow2;
30 import io.netty.util.internal.shaded.org.jctools.util.UnsafeAccess;
31
32 import java.io.BufferedReader;
33 import java.io.File;
34 import java.io.FileInputStream;
35 import java.io.IOException;
36 import java.io.InputStreamReader;
37 import java.lang.reflect.Field;
38 import java.lang.reflect.Method;
39 import java.nio.ByteBuffer;
40 import java.nio.ByteOrder;
41 import java.security.AccessController;
42 import java.security.PrivilegedAction;
43 import java.util.Arrays;
44 import java.util.Collections;
45 import java.util.Deque;
46 import java.util.HashSet;
47 import java.util.LinkedHashSet;
48 import java.util.List;
49 import java.util.Locale;
50 import java.util.Map;
51 import java.util.Queue;
52 import java.util.Random;
53 import java.util.Set;
54 import java.util.concurrent.ConcurrentHashMap;
55 import java.util.concurrent.ConcurrentLinkedDeque;
56 import java.util.concurrent.ConcurrentMap;
57 import java.util.concurrent.LinkedBlockingDeque;
58 import java.util.concurrent.atomic.AtomicLong;
59 import java.util.regex.Matcher;
60 import java.util.regex.Pattern;
61
62 import static io.netty.util.internal.PlatformDependent0.HASH_CODE_ASCII_SEED;
63 import static io.netty.util.internal.PlatformDependent0.HASH_CODE_C1;
64 import static io.netty.util.internal.PlatformDependent0.HASH_CODE_C2;
65 import static io.netty.util.internal.PlatformDependent0.hashCodeAsciiSanitize;
66 import static io.netty.util.internal.PlatformDependent0.unalignedAccess;
67 import static java.lang.Math.max;
68 import static java.lang.Math.min;
69
70 /**
71  * Utility that detects various properties specific to the current runtime
72  * environment, such as Java version and the availability of the
73  * {@code sun.misc.Unsafe} object.
74  * <p>
75  * You can disable the use of {@code sun.misc.Unsafe} if you specify
76  * the system property <strong>io.netty.noUnsafe</strong>.
77  */

78 public final class PlatformDependent {
79
80     private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent.class);
81
82     private static final Pattern MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN = Pattern.compile(
83             "\\s*-XX:MaxDirectMemorySize\\s*=\\s*([0-9]+)\\s*([kKmMgG]?)\\s*$");
84
85     private static final boolean IS_WINDOWS = isWindows0();
86     private static final boolean IS_OSX = isOsx0();
87     private static final boolean IS_J9_JVM = isJ9Jvm0();
88     private static final boolean IS_IVKVM_DOT_NET = isIkvmDotNet0();
89
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 = maxDirectMemory0();
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 int ADDRESS_SIZE = addressSize0();
115     private static final boolean USE_DIRECT_BUFFER_NO_CLEANER;
116     private static final AtomicLong DIRECT_MEMORY_COUNTER;
117     private static final long DIRECT_MEMORY_LIMIT;
118     private static final ThreadLocalRandomProvider RANDOM_PROVIDER;
119     private static final Cleaner CLEANER;
120     private static final int UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD;
121     // For specifications, see https://www.freedesktop.org/software/systemd/man/os-release.html
122     private static final String[] OS_RELEASE_FILES = {"/etc/os-release""/usr/lib/os-release"};
123     private static final String LINUX_ID_PREFIX = "ID=";
124     private static final String LINUX_ID_LIKE_PREFIX = "ID_LIKE=";
125     public static final boolean BIG_ENDIAN_NATIVE_ORDER = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
126
127     private static final Cleaner NOOP = new Cleaner() {
128         @Override
129         public void freeDirectBuffer(ByteBuffer buffer) {
130             // NOOP
131         }
132     };
133
134     static {
135         if (javaVersion() >= 7) {
136             RANDOM_PROVIDER = new ThreadLocalRandomProvider() {
137                 @Override
138                 @SuppressJava6Requirement(reason = "Usage guarded by java version check")
139                 public Random current() {
140                     return java.util.concurrent.ThreadLocalRandom.current();
141                 }
142             };
143         } else {
144             RANDOM_PROVIDER = new ThreadLocalRandomProvider() {
145                 @Override
146                 public Random current() {
147                     return ThreadLocalRandom.current();
148                 }
149             };
150         }
151
152         // Here is how the system property is used:
153         //
154         // * <  0  - Don't use cleaner, and inherit max direct memory from java. In this case the
155         //           "practical max direct memory" would be 2 * max memory as defined by the JDK.
156         // * == 0  - Use cleaner, Netty will not enforce max memory, and instead will defer to JDK.
157         // * >  0  - Don't use cleaner. This will limit Netty's total direct memory
158         //           (note: that JDK's direct memory limit is independent of this).
159         long maxDirectMemory = SystemPropertyUtil.getLong("io.netty.maxDirectMemory", -1);
160
161         if (maxDirectMemory == 0 || !hasUnsafe() || !PlatformDependent0.hasDirectBufferNoCleanerConstructor()) {
162             USE_DIRECT_BUFFER_NO_CLEANER = false;
163             DIRECT_MEMORY_COUNTER = null;
164         } else {
165             USE_DIRECT_BUFFER_NO_CLEANER = true;
166             if (maxDirectMemory < 0) {
167                 maxDirectMemory = MAX_DIRECT_MEMORY;
168                 if (maxDirectMemory <= 0) {
169                     DIRECT_MEMORY_COUNTER = null;
170                 } else {
171                     DIRECT_MEMORY_COUNTER = new AtomicLong();
172                 }
173             } else {
174                 DIRECT_MEMORY_COUNTER = new AtomicLong();
175             }
176         }
177         logger.debug("-Dio.netty.maxDirectMemory: {} bytes", maxDirectMemory);
178         DIRECT_MEMORY_LIMIT = maxDirectMemory >= 1 ? maxDirectMemory : MAX_DIRECT_MEMORY;
179
180         int tryAllocateUninitializedArray =
181                 SystemPropertyUtil.getInt("io.netty.uninitializedArrayAllocationThreshold", 1024);
182         UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD = javaVersion() >= 9 && PlatformDependent0.hasAllocateArrayMethod() ?
183                 tryAllocateUninitializedArray : -1;
184         logger.debug("-Dio.netty.uninitializedArrayAllocationThreshold: {}", UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD);
185
186         MAYBE_SUPER_USER = maybeSuperUser0();
187
188         if (!isAndroid()) {
189             // only direct to method if we are not running on android.
190             // See https://github.com/netty/netty/issues/2604
191             if (javaVersion() >= 9) {
192                 CLEANER = CleanerJava9.isSupported() ? new CleanerJava9() : NOOP;
193             } else {
194                 CLEANER = CleanerJava6.isSupported() ? new CleanerJava6() : NOOP;
195             }
196         } else {
197             CLEANER = NOOP;
198         }
199
200         // We should always prefer direct buffers by default if we can use a Cleaner to release direct buffers.
201         DIRECT_BUFFER_PREFERRED = CLEANER != NOOP
202                                   && !SystemPropertyUtil.getBoolean("io.netty.noPreferDirect"false);
203         if (logger.isDebugEnabled()) {
204             logger.debug("-Dio.netty.noPreferDirect: {}", !DIRECT_BUFFER_PREFERRED);
205         }
206
207         /*
208          * We do not want to log this message if unsafe is explicitly disabled. Do not remove the explicit no unsafe
209          * guard.
210          */

211         if (CLEANER == NOOP && !PlatformDependent0.isExplicitNoUnsafe()) {
212             logger.info(
213                     "Your platform does not provide complete low-level API for accessing direct buffers reliably. " +
214                     "Unless explicitly requested, heap buffer will always be preferred to avoid potential system " +
215                     "instability.");
216         }
217
218         final Set<String> allowedClassifiers = Collections.unmodifiableSet(
219                 new HashSet<String>(Arrays.asList(ALLOWED_LINUX_OS_CLASSIFIERS)));
220         final Set<String> availableClassifiers = new LinkedHashSet<String>();
221         for (final String osReleaseFileName : OS_RELEASE_FILES) {
222             final File file = new File(osReleaseFileName);
223             boolean found = AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
224                 @Override
225                 public Boolean run() {
226                     try {
227                         if (file.exists()) {
228                             BufferedReader reader = null;
229                             try {
230                                 reader = new BufferedReader(
231                                         new InputStreamReader(
232                                                 new FileInputStream(file), CharsetUtil.UTF_8));
233
234                                 String line;
235                                 while ((line = reader.readLine()) != null) {
236                                     if (line.startsWith(LINUX_ID_PREFIX)) {
237                                         String id = normalizeOsReleaseVariableValue(
238                                                 line.substring(LINUX_ID_PREFIX.length()));
239                                         addClassifier(allowedClassifiers, availableClassifiers, id);
240                                     } else if (line.startsWith(LINUX_ID_LIKE_PREFIX)) {
241                                         line = normalizeOsReleaseVariableValue(
242                                                 line.substring(LINUX_ID_LIKE_PREFIX.length()));
243                                         addClassifier(allowedClassifiers, availableClassifiers, line.split("[ ]+"));
244                                     }
245                                 }
246                             } catch (SecurityException e) {
247                                 logger.debug("Unable to read {}", osReleaseFileName, e);
248                             } catch (IOException e) {
249                                 logger.debug("Error while reading content of {}", osReleaseFileName, e);
250                             } finally {
251                                 if (reader != null) {
252                                     try {
253                                         reader.close();
254                                     } catch (IOException ignored) {
255                                         // Ignore
256                                     }
257                                 }
258                             }
259                             // specification states we should only fall back if /etc/os-release does not exist
260                             return true;
261                         }
262                     } catch (SecurityException e) {
263                         logger.debug("Unable to check if {} exists", osReleaseFileName, e);
264                     }
265                     return false;
266                 }
267             });
268
269             if (found) {
270                 break;
271             }
272         }
273         LINUX_OS_CLASSIFIERS = Collections.unmodifiableSet(availableClassifiers);
274     }
275
276     public static long byteArrayBaseOffset() {
277         return BYTE_ARRAY_BASE_OFFSET;
278     }
279
280     public static boolean hasDirectBufferNoCleanerConstructor() {
281         return PlatformDependent0.hasDirectBufferNoCleanerConstructor();
282     }
283
284     public static byte[] allocateUninitializedArray(int size) {
285         return UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD < 0 || UNINITIALIZED_ARRAY_ALLOCATION_THRESHOLD > size ?
286                 new byte[size] : PlatformDependent0.allocateUninitializedArray(size);
287     }
288
289     /**
290      * Returns {@code trueif and only if the current platform is Android
291      */

292     public static boolean isAndroid() {
293         return PlatformDependent0.isAndroid();
294     }
295
296     /**
297      * Return {@code trueif the JVM is running on Windows
298      */

299     public static boolean isWindows() {
300         return IS_WINDOWS;
301     }
302
303     /**
304      * Return {@code trueif the JVM is running on OSX / MacOS
305      */

306     public static boolean isOsx() {
307         return IS_OSX;
308     }
309
310     /**
311      * Return {@code trueif the current user may be a super-user. Be aware that this is just an hint and so it may
312      * return false-positives.
313      */

314     public static boolean maybeSuperUser() {
315         return MAYBE_SUPER_USER;
316     }
317
318     /**
319      * Return the version of Java under which this library is used.
320      */

321     public static int javaVersion() {
322         return PlatformDependent0.javaVersion();
323     }
324
325     /**
326      * Returns {@code trueif and only if it is fine to enable TCP_NODELAY socket option by default.
327      */

328     public static boolean canEnableTcpNoDelayByDefault() {
329         return CAN_ENABLE_TCP_NODELAY_BY_DEFAULT;
330     }
331
332     /**
333      * Return {@code trueif {@code sun.misc.Unsafe} was found on the classpath and can be used for accelerated
334      * direct memory access.
335      */

336     public static boolean hasUnsafe() {
337         return UNSAFE_UNAVAILABILITY_CAUSE == null;
338     }
339
340     /**
341      * Return the reason (if any) why {@code sun.misc.Unsafe} was not available.
342      */

343     public static Throwable getUnsafeUnavailabilityCause() {
344         return UNSAFE_UNAVAILABILITY_CAUSE;
345     }
346
347     /**
348      * {@code trueif and only if the platform supports unaligned access.
349      *
350      * @see <a href="http://en.wikipedia.org/wiki/Segmentation_fault#Bus_error">Wikipedia on segfault</a>
351      */

352     public static boolean isUnaligned() {
353         return PlatformDependent0.isUnaligned();
354     }
355
356     /**
357      * Returns {@code trueif the platform has reliable low-level direct buffer access API and a user has not specified
358      * {@code -Dio.netty.noPreferDirect} option.
359      */

360     public static boolean directBufferPreferred() {
361         return DIRECT_BUFFER_PREFERRED;
362     }
363
364     /**
365      * Returns the maximum memory reserved for direct buffer allocation.
366      */

367     public static long maxDirectMemory() {
368         return DIRECT_MEMORY_LIMIT;
369     }
370
371     /**
372      * Returns the current memory reserved for direct buffer allocation.
373      * This method returns -1 in case that a value is not available.
374      *
375      * @see #maxDirectMemory()
376      */

377     public static long usedDirectMemory() {
378         return DIRECT_MEMORY_COUNTER != null ? DIRECT_MEMORY_COUNTER.get() : -1;
379     }
380
381     /**
382      * Returns the temporary directory.
383      */

384     public static File tmpdir() {
385         return TMPDIR;
386     }
387
388     /**
389      * Returns the bit mode of the current VM (usually 32 or 64.)
390      */

391     public static int bitMode() {
392         return BIT_MODE;
393     }
394
395     /**
396      * Return the address size of the OS.
397      * 4 (for 32 bits systems ) and 8 (for 64 bits systems).
398      */

399     public static int addressSize() {
400         return ADDRESS_SIZE;
401     }
402
403     public static long allocateMemory(long size) {
404         return PlatformDependent0.allocateMemory(size);
405     }
406
407     public static void freeMemory(long address) {
408         PlatformDependent0.freeMemory(address);
409     }
410
411     public static long reallocateMemory(long address, long newSize) {
412         return PlatformDependent0.reallocateMemory(address, newSize);
413     }
414
415     /**
416      * Raises an exception bypassing compiler checks for checked exceptions.
417      */

418     public static void throwException(Throwable t) {
419         if (hasUnsafe()) {
420             PlatformDependent0.throwException(t);
421         } else {
422             PlatformDependent.<RuntimeException>throwException0(t);
423         }
424     }
425
426     @SuppressWarnings("unchecked")
427     private static <E extends Throwable> void throwException0(Throwable t) throws E {
428         throw (E) t;
429     }
430
431     /**
432      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
433      */

434     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap() {
435         return new ConcurrentHashMap<K, V>();
436     }
437
438     /**
439      * Creates a new fastest {@link LongCounter} implementation for the current platform.
440      */

441     public static LongCounter newLongCounter() {
442         if (javaVersion() >= 8) {
443             return new LongAdderCounter();
444         } else {
445             return new AtomicLongCounter();
446         }
447     }
448
449     /**
450      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
451      */

452     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(int initialCapacity) {
453         return new ConcurrentHashMap<K, V>(initialCapacity);
454     }
455
456     /**
457      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
458      */

459     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(int initialCapacity, float loadFactor) {
460         return new ConcurrentHashMap<K, V>(initialCapacity, loadFactor);
461     }
462
463     /**
464      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
465      */

466     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(
467             int initialCapacity, float loadFactor, int concurrencyLevel) {
468         return new ConcurrentHashMap<K, V>(initialCapacity, loadFactor, concurrencyLevel);
469     }
470
471     /**
472      * Creates a new fastest {@link ConcurrentMap} implementation for the current platform.
473      */

474     public static <K, V> ConcurrentMap<K, V> newConcurrentHashMap(Map<? extends K, ? extends V> map) {
475         return new ConcurrentHashMap<K, V>(map);
476     }
477
478     /**
479      * Try to deallocate the specified direct {@link ByteBuffer}. Please note this method does nothing if
480      * the current platform does not support this operation or the specified buffer is not a direct buffer.
481      */

482     public static void freeDirectBuffer(ByteBuffer buffer) {
483         CLEANER.freeDirectBuffer(buffer);
484     }
485
486     public static long directBufferAddress(ByteBuffer buffer) {
487         return PlatformDependent0.directBufferAddress(buffer);
488     }
489
490     public static ByteBuffer directBuffer(long memoryAddress, int size) {
491         if (PlatformDependent0.hasDirectBufferNoCleanerConstructor()) {
492             return PlatformDependent0.newDirectBuffer(memoryAddress, size);
493         }
494         throw new UnsupportedOperationException(
495                 "sun.misc.Unsafe or java.nio.DirectByteBuffer.<init>(longint) not available");
496     }
497
498     public static Object getObject(Object object, long fieldOffset) {
499         return PlatformDependent0.getObject(object, fieldOffset);
500     }
501
502     public static int getInt(Object object, long fieldOffset) {
503         return PlatformDependent0.getInt(object, fieldOffset);
504     }
505
506     public static byte getByte(long address) {
507         return PlatformDependent0.getByte(address);
508     }
509
510     public static short getShort(long address) {
511         return PlatformDependent0.getShort(address);
512     }
513
514     public static int getInt(long address) {
515         return PlatformDependent0.getInt(address);
516     }
517
518     public static long getLong(long address) {
519         return PlatformDependent0.getLong(address);
520     }
521
522     public static byte getByte(byte[] data, int index) {
523         return PlatformDependent0.getByte(data, index);
524     }
525
526     public static byte getByte(byte[] data, long index) {
527         return PlatformDependent0.getByte(data, index);
528     }
529
530     public static short getShort(byte[] data, int index) {
531         return PlatformDependent0.getShort(data, index);
532     }
533
534     public static int getInt(byte[] data, int index) {
535         return PlatformDependent0.getInt(data, index);
536     }
537
538     public static int getInt(int[] data, long index) {
539         return PlatformDependent0.getInt(data, index);
540     }
541
542     public static long getLong(byte[] data, int index) {
543         return PlatformDependent0.getLong(data, index);
544     }
545
546     public static long getLong(long[] data, long index) {
547         return PlatformDependent0.getLong(data, index);
548     }
549
550     private static long getLongSafe(byte[] bytes, int offset) {
551         if (BIG_ENDIAN_NATIVE_ORDER) {
552             return (long) bytes[offset] << 56 |
553                     ((long) bytes[offset + 1] & 0xff) << 48 |
554                     ((long) bytes[offset + 2] & 0xff) << 40 |
555                     ((long) bytes[offset + 3] & 0xff) << 32 |
556                     ((long) bytes[offset + 4] & 0xff) << 24 |
557                     ((long) bytes[offset + 5] & 0xff) << 16 |
558                     ((long) bytes[offset + 6] & 0xff) <<  8 |
559                     (long) bytes[offset + 7] & 0xff;
560         }
561         return (long) bytes[offset] & 0xff |
562                 ((long) bytes[offset + 1] & 0xff) << 8 |
563                 ((long) bytes[offset + 2] & 0xff) << 16 |
564                 ((long) bytes[offset + 3] & 0xff) << 24 |
565                 ((long) bytes[offset + 4] & 0xff) << 32 |
566                 ((long) bytes[offset + 5] & 0xff) << 40 |
567                 ((long) bytes[offset + 6] & 0xff) << 48 |
568                 (long) bytes[offset + 7] << 56;
569     }
570
571     private static int getIntSafe(byte[] bytes, int offset) {
572         if (BIG_ENDIAN_NATIVE_ORDER) {
573             return bytes[offset] << 24 |
574                     (bytes[offset + 1] & 0xff) << 16 |
575                     (bytes[offset + 2] & 0xff) << 8 |
576                     bytes[offset + 3] & 0xff;
577         }
578         return bytes[offset] & 0xff |
579                 (bytes[offset + 1] & 0xff) << 8 |
580                 (bytes[offset + 2] & 0xff) << 16 |
581                 bytes[offset + 3] << 24;
582     }
583
584     private static short getShortSafe(byte[] bytes, int offset) {
585         if (BIG_ENDIAN_NATIVE_ORDER) {
586             return (short) (bytes[offset] << 8 | (bytes[offset + 1] & 0xff));
587         }
588         return (short) (bytes[offset] & 0xff | (bytes[offset + 1] << 8));
589     }
590
591     /**
592      * Identical to {@link PlatformDependent0#hashCodeAsciiCompute(longint)} but for {@link CharSequence}.
593      */

594     private static int hashCodeAsciiCompute(CharSequence value, int offset, int hash) {
595         if (BIG_ENDIAN_NATIVE_ORDER) {
596             return hash * HASH_CODE_C1 +
597                     // Low order int
598                     hashCodeAsciiSanitizeInt(value, offset + 4) * HASH_CODE_C2 +
599                     // High order int
600                     hashCodeAsciiSanitizeInt(value, offset);
601         }
602         return hash * HASH_CODE_C1 +
603                 // Low order int
604                 hashCodeAsciiSanitizeInt(value, offset) * HASH_CODE_C2 +
605                 // High order int
606                 hashCodeAsciiSanitizeInt(value, offset + 4);
607     }
608
609     /**
610      * Identical to {@link PlatformDependent0#hashCodeAsciiSanitize(int)} but for {@link CharSequence}.
611      */

612     private static int hashCodeAsciiSanitizeInt(CharSequence value, int offset) {
613         if (BIG_ENDIAN_NATIVE_ORDER) {
614             // mimic a unsafe.getInt call on a big endian machine
615             return (value.charAt(offset + 3) & 0x1f) |
616                    (value.charAt(offset + 2) & 0x1f) << 8 |
617                    (value.charAt(offset + 1) & 0x1f) << 16 |
618                    (value.charAt(offset) & 0x1f) << 24;
619         }
620         return (value.charAt(offset + 3) & 0x1f) << 24 |
621                (value.charAt(offset + 2) & 0x1f) << 16 |
622                (value.charAt(offset + 1) & 0x1f) << 8 |
623                (value.charAt(offset) & 0x1f);
624     }
625
626     /**
627      * Identical to {@link PlatformDependent0#hashCodeAsciiSanitize(short)} but for {@link CharSequence}.
628      */

629     private static int hashCodeAsciiSanitizeShort(CharSequence value, int offset) {
630         if (BIG_ENDIAN_NATIVE_ORDER) {
631             // mimic a unsafe.getShort call on a big endian machine
632             return (value.charAt(offset + 1) & 0x1f) |
633                     (value.charAt(offset) & 0x1f) << 8;
634         }
635         return (value.charAt(offset + 1) & 0x1f) << 8 |
636                 (value.charAt(offset) & 0x1f);
637     }
638
639     /**
640      * Identical to {@link PlatformDependent0#hashCodeAsciiSanitize(byte)} but for {@link CharSequence}.
641      */

642     private static int hashCodeAsciiSanitizeByte(char value) {
643         return value & 0x1f;
644     }
645
646     public static void putByte(long address, byte value) {
647         PlatformDependent0.putByte(address, value);
648     }
649
650     public static void putShort(long address, short value) {
651         PlatformDependent0.putShort(address, value);
652     }
653
654     public static void putInt(long address, int value) {
655         PlatformDependent0.putInt(address, value);
656     }
657
658     public static void putLong(long address, long value) {
659         PlatformDependent0.putLong(address, value);
660     }
661
662     public static void putByte(byte[] data, int index, byte value) {
663         PlatformDependent0.putByte(data, index, value);
664     }
665
666     public static void putByte(Object data, long offset, byte value) {
667         PlatformDependent0.putByte(data, offset, value);
668     }
669
670     public static void putShort(byte[] data, int index, short value) {
671         PlatformDependent0.putShort(data, index, value);
672     }
673
674     public static void putInt(byte[] data, int index, int value) {
675         PlatformDependent0.putInt(data, index, value);
676     }
677
678     public static void putLong(byte[] data, int index, long value) {
679         PlatformDependent0.putLong(data, index, value);
680     }
681
682     public static void putObject(Object o, long offset, Object x) {
683         PlatformDependent0.putObject(o, offset, x);
684     }
685
686     public static long objectFieldOffset(Field field) {
687         return PlatformDependent0.objectFieldOffset(field);
688     }
689
690     public static void copyMemory(long srcAddr, long dstAddr, long length) {
691         PlatformDependent0.copyMemory(srcAddr, dstAddr, length);
692     }
693
694     public static void copyMemory(byte[] src, int srcIndex, long dstAddr, long length) {
695         PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex, null, dstAddr, length);
696     }
697
698     public static void copyMemory(byte[] src, int srcIndex, byte[] dst, int dstIndex, long length) {
699         PlatformDependent0.copyMemory(src, BYTE_ARRAY_BASE_OFFSET + srcIndex,
700                                       dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
701     }
702
703     public static void copyMemory(long srcAddr, byte[] dst, int dstIndex, long length) {
704         PlatformDependent0.copyMemory(null, srcAddr, dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, length);
705     }
706
707     public static void setMemory(byte[] dst, int dstIndex, long bytes, byte value) {
708         PlatformDependent0.setMemory(dst, BYTE_ARRAY_BASE_OFFSET + dstIndex, bytes, value);
709     }
710
711     public static void setMemory(long address, long bytes, byte value) {
712         PlatformDependent0.setMemory(address, bytes, value);
713     }
714
715     /**
716      * Allocate a new {@link ByteBuffer} with the given {@code capacity}. {@link ByteBuffer}s allocated with
717      * this method <strong>MUST</strong> be deallocated via {@link #freeDirectNoCleaner(ByteBuffer)}.
718      */

719     public static ByteBuffer allocateDirectNoCleaner(int capacity) {
720         assert USE_DIRECT_BUFFER_NO_CLEANER;
721
722         incrementMemoryCounter(capacity);
723         try {
724             return PlatformDependent0.allocateDirectNoCleaner(capacity);
725         } catch (Throwable e) {
726             decrementMemoryCounter(capacity);
727             throwException(e);
728             return null;
729         }
730     }
731
732     /**
733      * Reallocate a new {@link ByteBuffer} with the given {@code capacity}. {@link ByteBuffer}s reallocated with
734      * this method <strong>MUST</strong> be deallocated via {@link #freeDirectNoCleaner(ByteBuffer)}.
735      */

736     public static ByteBuffer reallocateDirectNoCleaner(ByteBuffer buffer, int capacity) {
737         assert USE_DIRECT_BUFFER_NO_CLEANER;
738
739         int len = capacity - buffer.capacity();
740         incrementMemoryCounter(len);
741         try {
742             return PlatformDependent0.reallocateDirectNoCleaner(buffer, capacity);
743         } catch (Throwable e) {
744             decrementMemoryCounter(len);
745             throwException(e);
746             return null;
747         }
748     }
749
750     /**
751      * This method <strong>MUST</strong> only be called for {@link ByteBuffer}s that were allocated via
752      * {@link #allocateDirectNoCleaner(int)}.
753      */

754     public static void freeDirectNoCleaner(ByteBuffer buffer) {
755         assert USE_DIRECT_BUFFER_NO_CLEANER;
756
757         int capacity = buffer.capacity();
758         PlatformDependent0.freeMemory(PlatformDependent0.directBufferAddress(buffer));
759         decrementMemoryCounter(capacity);
760     }
761
762     private static void incrementMemoryCounter(int capacity) {
763         if (DIRECT_MEMORY_COUNTER != null) {
764             long newUsedMemory = DIRECT_MEMORY_COUNTER.addAndGet(capacity);
765             if (newUsedMemory > DIRECT_MEMORY_LIMIT) {
766                 DIRECT_MEMORY_COUNTER.addAndGet(-capacity);
767                 throw new OutOfDirectMemoryError("failed to allocate " + capacity
768                         + byte(s) of direct memory (used: " + (newUsedMemory - capacity)
769                         + ", max: " + DIRECT_MEMORY_LIMIT + ')');
770             }
771         }
772     }
773
774     private static void decrementMemoryCounter(int capacity) {
775         if (DIRECT_MEMORY_COUNTER != null) {
776             long usedMemory = DIRECT_MEMORY_COUNTER.addAndGet(-capacity);
777             assert usedMemory >= 0;
778         }
779     }
780
781     public static boolean useDirectBufferNoCleaner() {
782         return USE_DIRECT_BUFFER_NO_CLEANER;
783     }
784
785     /**
786      * Compare two {@code byte} arrays for equality. For performance reasons no bounds checking on the
787      * parameters is performed.
788      *
789      * @param bytes1 the first byte array.
790      * @param startPos1 the position (inclusive) to start comparing in {@code bytes1}.
791      * @param bytes2 the second byte array.
792      * @param startPos2 the position (inclusive) to start comparing in {@code bytes2}.
793      * @param length the amount of bytes to compare. This is assumed to be validated as not going out of bounds
794      * by the caller.
795      */

796     public static boolean equals(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
797         return !hasUnsafe() || !unalignedAccess() ?
798                   equalsSafe(bytes1, startPos1, bytes2, startPos2, length) :
799                   PlatformDependent0.equals(bytes1, startPos1, bytes2, startPos2, length);
800     }
801
802     /**
803      * Determine if a subsection of an array is zero.
804      * @param bytes The byte array.
805      * @param startPos The starting index (inclusive) in {@code bytes}.
806      * @param length The amount of bytes to check for zero.
807      * @return {@code falseif {@code bytes[startPos:startsPos+length)} contains a value other than zero.
808      */

809     public static boolean isZero(byte[] bytes, int startPos, int length) {
810         return !hasUnsafe() || !unalignedAccess() ?
811                 isZeroSafe(bytes, startPos, length) :
812                 PlatformDependent0.isZero(bytes, startPos, length);
813     }
814
815     /**
816      * Compare two {@code byte} arrays for equality without leaking timing information.
817      * For performance reasons no bounds checking on the parameters is performed.
818      * <p>
819      * The {@code intreturn type is intentional and is designed to allow cascading of constant time operations:
820      * <pre>
821      *     byte[] s1 = new {1, 2, 3};
822      *     byte[] s2 = new {1, 2, 3};
823      *     byte[] s3 = new {1, 2, 3};
824      *     byte[] s4 = new {4, 5, 6};
825      *     boolean equals = (equalsConstantTime(s1, 0, s2, 0, s1.length) &
826      *                       equalsConstantTime(s3, 0, s4, 0, s3.length)) != 0;
827      * </pre>
828      * @param bytes1 the first byte array.
829      * @param startPos1 the position (inclusive) to start comparing in {@code bytes1}.
830      * @param bytes2 the second byte array.
831      * @param startPos2 the position (inclusive) to start comparing in {@code bytes2}.
832      * @param length the amount of bytes to compare. This is assumed to be validated as not going out of bounds
833      * by the caller.
834      * @return {@code 0} if not equal. {@code 1} if equal.
835      */

836     public static int equalsConstantTime(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
837         return !hasUnsafe() || !unalignedAccess() ?
838                   ConstantTimeUtils.equalsConstantTime(bytes1, startPos1, bytes2, startPos2, length) :
839                   PlatformDependent0.equalsConstantTime(bytes1, startPos1, bytes2, startPos2, length);
840     }
841
842     /**
843      * Calculate a hash code of a byte array assuming ASCII character encoding.
844      * The resulting hash code will be case insensitive.
845      * @param bytes The array which contains the data to hash.
846      * @param startPos What index to start generating a hash code in {@code bytes}
847      * @param length The amount of bytes that should be accounted for in the computation.
848      * @return The hash code of {@code bytes} assuming ASCII character encoding.
849      * The resulting hash code will be case insensitive.
850      */

851     public static int hashCodeAscii(byte[] bytes, int startPos, int length) {
852         return !hasUnsafe() || !unalignedAccess() ?
853                 hashCodeAsciiSafe(bytes, startPos, length) :
854                 PlatformDependent0.hashCodeAscii(bytes, startPos, length);
855     }
856
857     /**
858      * Calculate a hash code of a byte array assuming ASCII character encoding.
859      * The resulting hash code will be case insensitive.
860      * <p>
861      * This method assumes that {@code bytes} is equivalent to a {@code byte[]} but just using {@link CharSequence}
862      * for storage. The upper most byte of each {@code char} from {@code bytes} is ignored.
863      * @param bytes The array which contains the data to hash (assumed to be equivalent to a {@code byte[]}).
864      * @return The hash code of {@code bytes} assuming ASCII character encoding.
865      * The resulting hash code will be case insensitive.
866      */

867     public static int hashCodeAscii(CharSequence bytes) {
868         final int length = bytes.length();
869         final int remainingBytes = length & 7;
870         int hash = HASH_CODE_ASCII_SEED;
871         // Benchmarking shows that by just naively looping for inputs 8~31 bytes long we incur a relatively large
872         // performance penalty (only achieve about 60% performance of loop which iterates over each char). So because
873         // of this we take special provisions to unroll the looping for these conditions.
874         if (length >= 32) {
875             for (int i = length - 8; i >= remainingBytes; i -= 8) {
876                 hash = hashCodeAsciiCompute(bytes, i, hash);
877             }
878         } else if (length >= 8) {
879             hash = hashCodeAsciiCompute(bytes, length - 8, hash);
880             if (length >= 16) {
881                 hash = hashCodeAsciiCompute(bytes, length - 16, hash);
882                 if (length >= 24) {
883                     hash = hashCodeAsciiCompute(bytes, length - 24, hash);
884                 }
885             }
886         }
887         if (remainingBytes == 0) {
888             return hash;
889         }
890         int offset = 0;
891         if (remainingBytes != 2 & remainingBytes != 4 & remainingBytes != 6) { // 1, 3, 5, 7
892             hash = hash * HASH_CODE_C1 + hashCodeAsciiSanitizeByte(bytes.charAt(0));
893             offset = 1;
894         }
895         if (remainingBytes != 1 & remainingBytes != 4 & remainingBytes != 5) { // 2, 3, 6, 7
896             hash = hash * (offset == 0 ? HASH_CODE_C1 : HASH_CODE_C2)
897                     + hashCodeAsciiSanitize(hashCodeAsciiSanitizeShort(bytes, offset));
898             offset += 2;
899         }
900         if (remainingBytes >= 4) { // 4, 5, 6, 7
901             return hash * ((offset == 0 | offset == 3) ? HASH_CODE_C1 : HASH_CODE_C2)
902                     + hashCodeAsciiSanitizeInt(bytes, offset);
903         }
904         return hash;
905     }
906
907     private static final class Mpsc {
908         private static final boolean USE_MPSC_CHUNKED_ARRAY_QUEUE;
909
910         private Mpsc() {
911         }
912
913         static {
914             Object unsafe = null;
915             if (hasUnsafe()) {
916                 // jctools goes through its own process of initializing unsafe; of
917                 // course, this requires permissions which might not be granted to calling code, so we
918                 // must mark this block as privileged too
919                 unsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
920                     @Override
921                     public Object run() {
922                         // force JCTools to initialize unsafe
923                         return UnsafeAccess.UNSAFE;
924                     }
925                 });
926             }
927
928             if (unsafe == null) {
929                 logger.debug("io.netty.util.internal.shaded.org.jctools.core.MpscChunkedArrayQueue: unavailable");
930                 USE_MPSC_CHUNKED_ARRAY_QUEUE = false;
931             } else {
932                 logger.debug("io.netty.util.internal.shaded.org.jctools.core.MpscChunkedArrayQueue: available");
933                 USE_MPSC_CHUNKED_ARRAY_QUEUE = true;
934             }
935         }
936
937         static <T> Queue<T> newMpscQueue(final int maxCapacity) {
938             // Calculate the max capacity which can not be bigger than MAX_ALLOWED_MPSC_CAPACITY.
939             // This is forced by the MpscChunkedArrayQueue implementation as will try to round it
940             // up to the next power of two and so will overflow otherwise.
941             final int capacity = max(min(maxCapacity, MAX_ALLOWED_MPSC_CAPACITY), MIN_MAX_MPSC_CAPACITY);
942             return USE_MPSC_CHUNKED_ARRAY_QUEUE ? new MpscChunkedArrayQueue<T>(MPSC_CHUNK_SIZE, capacity)
943                                                 : new MpscChunkedAtomicArrayQueue<T>(MPSC_CHUNK_SIZE, capacity);
944         }
945
946         static <T> Queue<T> newMpscQueue() {
947             return USE_MPSC_CHUNKED_ARRAY_QUEUE ? new MpscUnboundedArrayQueue<T>(MPSC_CHUNK_SIZE)
948                                                 : new MpscUnboundedAtomicArrayQueue<T>(MPSC_CHUNK_SIZE);
949         }
950     }
951
952     /**
953      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
954      * consumer (one thread!).
955      * @return A MPSC queue which may be unbounded.
956      */

957     public static <T> Queue<T> newMpscQueue() {
958         return Mpsc.newMpscQueue();
959     }
960
961     /**
962      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
963      * consumer (one thread!).
964      */

965     public static <T> Queue<T> newMpscQueue(final int maxCapacity) {
966         return Mpsc.newMpscQueue(maxCapacity);
967     }
968
969     /**
970      * Create a new {@link Queue} which is safe to use for single producer (one thread!) and a single
971      * consumer (one thread!).
972      */

973     public static <T> Queue<T> newSpscQueue() {
974         return hasUnsafe() ? new SpscLinkedQueue<T>() : new SpscLinkedAtomicQueue<T>();
975     }
976
977     /**
978      * Create a new {@link Queue} which is safe to use for multiple producers (different threads) and a single
979      * consumer (one thread!) with the given fixes {@code capacity}.
980      */

981     public static <T> Queue<T> newFixedMpscQueue(int capacity) {
982         return hasUnsafe() ? new MpscArrayQueue<T>(capacity) : new MpscAtomicArrayQueue<T>(capacity);
983     }
984
985     /**
986      * Return the {@link ClassLoader} for the given {@link Class}.
987      */

988     public static ClassLoader getClassLoader(final Class<?> clazz) {
989         return PlatformDependent0.getClassLoader(clazz);
990     }
991
992     /**
993      * Return the context {@link ClassLoader} for the current {@link Thread}.
994      */

995     public static ClassLoader getContextClassLoader() {
996         return PlatformDependent0.getContextClassLoader();
997     }
998
999     /**
1000      * Return the system {@link ClassLoader}.
1001      */

1002     public static ClassLoader getSystemClassLoader() {
1003         return PlatformDependent0.getSystemClassLoader();
1004     }
1005
1006     /**
1007      * Returns a new concurrent {@link Deque}.
1008      */

1009     @SuppressJava6Requirement(reason = "Usage guarded by java version check")
1010     public static <C> Deque<C> newConcurrentDeque() {
1011         if (javaVersion() < 7) {
1012             return new LinkedBlockingDeque<C>();
1013         } else {
1014             return new ConcurrentLinkedDeque<C>();
1015         }
1016     }
1017
1018     /**
1019      * Return a {@link Random} which is not-threadsafe and so can only be used from the same thread.
1020      */

1021     public static Random threadLocalRandom() {
1022         return RANDOM_PROVIDER.current();
1023     }
1024
1025     private static boolean isWindows0() {
1026         boolean windows = SystemPropertyUtil.get("os.name""").toLowerCase(Locale.US).contains("win");
1027         if (windows) {
1028             logger.debug("Platform: Windows");
1029         }
1030         return windows;
1031     }
1032
1033     private static boolean isOsx0() {
1034         String osname = SystemPropertyUtil.get("os.name""").toLowerCase(Locale.US)
1035                 .replaceAll("[^a-z0-9]+""");
1036         boolean osx = osname.startsWith("macosx") || osname.startsWith("osx");
1037
1038         if (osx) {
1039             logger.debug("Platform: MacOS");
1040         }
1041         return osx;
1042     }
1043
1044     private static boolean maybeSuperUser0() {
1045         String username = SystemPropertyUtil.get("user.name");
1046         if (isWindows()) {
1047             return "Administrator".equals(username);
1048         }
1049         // Check for root and toor as some BSDs have a toor user that is basically the same as root.
1050         return "root".equals(username) || "toor".equals(username);
1051     }
1052
1053     private static Throwable unsafeUnavailabilityCause0() {
1054         if (isAndroid()) {
1055             logger.debug("sun.misc.Unsafe: unavailable (Android)");
1056             return new UnsupportedOperationException("sun.misc.Unsafe: unavailable (Android)");
1057         }
1058
1059         if (isIkvmDotNet()) {
1060             logger.debug("sun.misc.Unsafe: unavailable (IKVM.NET)");
1061             return new UnsupportedOperationException("sun.misc.Unsafe: unavailable (IKVM.NET)");
1062         }
1063
1064         Throwable cause = PlatformDependent0.getUnsafeUnavailabilityCause();
1065         if (cause != null) {
1066             return cause;
1067         }
1068
1069         try {
1070             boolean hasUnsafe = PlatformDependent0.hasUnsafe();
1071             logger.debug("sun.misc.Unsafe: {}", hasUnsafe ? "available" : "unavailable");
1072             return hasUnsafe ? null : PlatformDependent0.getUnsafeUnavailabilityCause();
1073         } catch (Throwable t) {
1074             logger.trace("Could not determine if Unsafe is available", t);
1075             // Probably failed to initialize PlatformDependent0.
1076             return new UnsupportedOperationException("Could not determine if Unsafe is available", t);
1077         }
1078     }
1079
1080     /**
1081      * Returns {@code trueif the running JVM is either <a href="https://developer.ibm.com/javasdk/">IBM J9</a> or
1082      * <a href="https://www.eclipse.org/openj9/">Eclipse OpenJ9</a>, {@code false} otherwise.
1083      */

1084     public static boolean isJ9Jvm() {
1085         return IS_J9_JVM;
1086     }
1087
1088     private static boolean isJ9Jvm0() {
1089         String vmName = SystemPropertyUtil.get("java.vm.name""").toLowerCase();
1090         return vmName.startsWith("ibm j9") || vmName.startsWith("eclipse openj9");
1091     }
1092
1093     /**
1094      * Returns {@code trueif the running JVM is <a href="https://www.ikvm.net">IKVM.NET</a>, {@code false} otherwise.
1095      */

1096     public static boolean isIkvmDotNet() {
1097         return IS_IVKVM_DOT_NET;
1098     }
1099
1100     private static boolean isIkvmDotNet0() {
1101         String vmName = SystemPropertyUtil.get("java.vm.name""").toUpperCase(Locale.US);
1102         return vmName.equals("IKVM.NET");
1103     }
1104
1105     private static long maxDirectMemory0() {
1106         long maxDirectMemory = 0;
1107
1108         ClassLoader systemClassLoader = null;
1109         try {
1110             systemClassLoader = getSystemClassLoader();
1111
1112             // When using IBM J9 / Eclipse OpenJ9 we should not use VM.maxDirectMemory() as it not reflects the
1113             // correct value.
1114             // See:
1115             //  - https://github.com/netty/netty/issues/7654
1116             String vmName = SystemPropertyUtil.get("java.vm.name""").toLowerCase();
1117             if (!vmName.startsWith("ibm j9") &&
1118                     // https://github.com/eclipse/openj9/blob/openj9-0.8.0/runtime/include/vendor_version.h#L53
1119                     !vmName.startsWith("eclipse openj9")) {
1120                 // Try to get from sun.misc.VM.maxDirectMemory() which should be most accurate.
1121                 Class<?> vmClass = Class.forName("sun.misc.VM"true, systemClassLoader);
1122                 Method m = vmClass.getDeclaredMethod("maxDirectMemory");
1123                 maxDirectMemory = ((Number) m.invoke(null)).longValue();
1124             }
1125         } catch (Throwable ignored) {
1126             // Ignore
1127         }
1128
1129         if (maxDirectMemory > 0) {
1130             return maxDirectMemory;
1131         }
1132
1133         try {
1134             // Now try to get the JVM option (-XX:MaxDirectMemorySize) and parse it.
1135             // Note that we are using reflection because Android doesn't have these classes.
1136             Class<?> mgmtFactoryClass = Class.forName(
1137                     "java.lang.management.ManagementFactory"true, systemClassLoader);
1138             Class<?> runtimeClass = Class.forName(
1139                     "java.lang.management.RuntimeMXBean"true, systemClassLoader);
1140
1141             Object runtime = mgmtFactoryClass.getDeclaredMethod("getRuntimeMXBean").invoke(null);
1142
1143             @SuppressWarnings("unchecked")
1144             List<String> vmArgs = (List<String>) runtimeClass.getDeclaredMethod("getInputArguments").invoke(runtime);
1145             for (int i = vmArgs.size() - 1; i >= 0; i --) {
1146                 Matcher m = MAX_DIRECT_MEMORY_SIZE_ARG_PATTERN.matcher(vmArgs.get(i));
1147                 if (!m.matches()) {
1148                     continue;
1149                 }
1150
1151                 maxDirectMemory = Long.parseLong(m.group(1));
1152                 switch (m.group(2).charAt(0)) {
1153                     case 'k': case 'K':
1154                         maxDirectMemory *= 1024;
1155                         break;
1156                     case 'm': case 'M':
1157                         maxDirectMemory *= 1024 * 1024;
1158                         break;
1159                     case 'g': case 'G':
1160                         maxDirectMemory *= 1024 * 1024 * 1024;
1161                         break;
1162                     default:
1163                         break;
1164                 }
1165                 break;
1166             }
1167         } catch (Throwable ignored) {
1168             // Ignore
1169         }
1170
1171         if (maxDirectMemory <= 0) {
1172             maxDirectMemory = Runtime.getRuntime().maxMemory();
1173             logger.debug("maxDirectMemory: {} bytes (maybe)", maxDirectMemory);
1174         } else {
1175             logger.debug("maxDirectMemory: {} bytes", maxDirectMemory);
1176         }
1177
1178         return maxDirectMemory;
1179     }
1180
1181     private static File tmpdir0() {
1182         File f;
1183         try {
1184             f = toDirectory(SystemPropertyUtil.get("io.netty.tmpdir"));
1185             if (f != null) {
1186                 logger.debug("-Dio.netty.tmpdir: {}", f);
1187                 return f;
1188             }
1189
1190             f = toDirectory(SystemPropertyUtil.get("java.io.tmpdir"));
1191             if (f != null) {
1192                 logger.debug("-Dio.netty.tmpdir: {} (java.io.tmpdir)", f);
1193                 return f;
1194             }
1195
1196             // This shouldn't happen, but just in case ..
1197             if (isWindows()) {
1198                 f = toDirectory(System.getenv("TEMP"));
1199                 if (f != null) {
1200                     logger.debug("-Dio.netty.tmpdir: {} (%TEMP%)", f);
1201                     return f;
1202                 }
1203
1204                 String userprofile = System.getenv("USERPROFILE");
1205                 if (userprofile != null) {
1206                     f = toDirectory(userprofile + "\\AppData\\Local\\Temp");
1207                     if (f != null) {
1208                         logger.debug("-Dio.netty.tmpdir: {} (%USERPROFILE%\\AppData\\Local\\Temp)", f);
1209                         return f;
1210                     }
1211
1212                     f = toDirectory(userprofile + "\\Local Settings\\Temp");
1213                     if (f != null) {
1214                         logger.debug("-Dio.netty.tmpdir: {} (%USERPROFILE%\\Local Settings\\Temp)", f);
1215                         return f;
1216                     }
1217                 }
1218             } else {
1219                 f = toDirectory(System.getenv("TMPDIR"));
1220                 if (f != null) {
1221                     logger.debug("-Dio.netty.tmpdir: {} ($TMPDIR)", f);
1222                     return f;
1223                 }
1224             }
1225         } catch (Throwable ignored) {
1226             // Environment variable inaccessible
1227         }
1228
1229         // Last resort.
1230         if (isWindows()) {
1231             f = new File("C:\\Windows\\Temp");
1232         } else {
1233             f = new File("/tmp");
1234         }
1235
1236         logger.warn("Failed to get the temporary directory; falling back to: {}", f);
1237         return f;
1238     }
1239
1240     @SuppressWarnings("ResultOfMethodCallIgnored")
1241     private static File toDirectory(String path) {
1242         if (path == null) {
1243             return null;
1244         }
1245
1246         File f = new File(path);
1247         f.mkdirs();
1248
1249         if (!f.isDirectory()) {
1250             return null;
1251         }
1252
1253         try {
1254             return f.getAbsoluteFile();
1255         } catch (Exception ignored) {
1256             return f;
1257         }
1258     }
1259
1260     private static int bitMode0() {
1261         // Check user-specified bit mode first.
1262         int bitMode = SystemPropertyUtil.getInt("io.netty.bitMode", 0);
1263         if (bitMode > 0) {
1264             logger.debug("-Dio.netty.bitMode: {}", bitMode);
1265             return bitMode;
1266         }
1267
1268         // And then the vendor specific ones which is probably most reliable.
1269         bitMode = SystemPropertyUtil.getInt("sun.arch.data.model", 0);
1270         if (bitMode > 0) {
1271             logger.debug("-Dio.netty.bitMode: {} (sun.arch.data.model)", bitMode);
1272             return bitMode;
1273         }
1274         bitMode = SystemPropertyUtil.getInt("com.ibm.vm.bitmode", 0);
1275         if (bitMode > 0) {
1276             logger.debug("-Dio.netty.bitMode: {} (com.ibm.vm.bitmode)", bitMode);
1277             return bitMode;
1278         }
1279
1280         // os.arch also gives us a good hint.
1281         String arch = SystemPropertyUtil.get("os.arch""").toLowerCase(Locale.US).trim();
1282         if ("amd64".equals(arch) || "x86_64".equals(arch)) {
1283             bitMode = 64;
1284         } else if ("i386".equals(arch) || "i486".equals(arch) || "i586".equals(arch) || "i686".equals(arch)) {
1285             bitMode = 32;
1286         }
1287
1288         if (bitMode > 0) {
1289             logger.debug("-Dio.netty.bitMode: {} (os.arch: {})", bitMode, arch);
1290         }
1291
1292         // Last resort: guess from VM name and then fall back to most common 64-bit mode.
1293         String vm = SystemPropertyUtil.get("java.vm.name""").toLowerCase(Locale.US);
1294         Pattern bitPattern = Pattern.compile("([1-9][0-9]+)-?bit");
1295         Matcher m = bitPattern.matcher(vm);
1296         if (m.find()) {
1297             return Integer.parseInt(m.group(1));
1298         } else {
1299             return 64;
1300         }
1301     }
1302
1303     private static int addressSize0() {
1304         if (!hasUnsafe()) {
1305             return -1;
1306         }
1307         return PlatformDependent0.addressSize();
1308     }
1309
1310     private static long byteArrayBaseOffset0() {
1311         if (!hasUnsafe()) {
1312             return -1;
1313         }
1314         return PlatformDependent0.byteArrayBaseOffset();
1315     }
1316
1317     private static boolean equalsSafe(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
1318         final int end = startPos1 + length;
1319         for (; startPos1 < end; ++startPos1, ++startPos2) {
1320             if (bytes1[startPos1] != bytes2[startPos2]) {
1321                 return false;
1322             }
1323         }
1324         return true;
1325     }
1326
1327     private static boolean isZeroSafe(byte[] bytes, int startPos, int length) {
1328         final int end = startPos + length;
1329         for (; startPos < end; ++startPos) {
1330             if (bytes[startPos] != 0) {
1331                 return false;
1332             }
1333         }
1334         return true;
1335     }
1336
1337     /**
1338      * Package private for testing purposes only!
1339      */

1340     static int hashCodeAsciiSafe(byte[] bytes, int startPos, int length) {
1341         int hash = HASH_CODE_ASCII_SEED;
1342         final int remainingBytes = length & 7;
1343         final int end = startPos + remainingBytes;
1344         for (int i = startPos - 8 + length; i >= end; i -= 8) {
1345             hash = PlatformDependent0.hashCodeAsciiCompute(getLongSafe(bytes, i), hash);
1346         }
1347         switch(remainingBytes) {
1348         case 7:
1349             return ((hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]))
1350                           * HASH_CODE_C2 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos + 1)))
1351                           * HASH_CODE_C1 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos + 3));
1352         case 6:
1353             return (hash * HASH_CODE_C1 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos)))
1354                          * HASH_CODE_C2 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos + 2));
1355         case 5:
1356             return (hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]))
1357                          * HASH_CODE_C2 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos + 1));
1358         case 4:
1359             return hash * HASH_CODE_C1 + hashCodeAsciiSanitize(getIntSafe(bytes, startPos));
1360         case 3:
1361             return (hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]))
1362                          * HASH_CODE_C2 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos + 1));
1363         case 2:
1364             return hash * HASH_CODE_C1 + hashCodeAsciiSanitize(getShortSafe(bytes, startPos));
1365         case 1:
1366             return hash * HASH_CODE_C1 + hashCodeAsciiSanitize(bytes[startPos]);
1367         default:
1368             return hash;
1369         }
1370     }
1371
1372     public static String normalizedArch() {
1373         return NORMALIZED_ARCH;
1374     }
1375
1376     public static String normalizedOs() {
1377         return NORMALIZED_OS;
1378     }
1379
1380     public static Set<String> normalizedLinuxClassifiers() {
1381         return LINUX_OS_CLASSIFIERS;
1382     }
1383
1384     /**
1385      * Adds only those classifier strings to <tt>dest</tt> which are present in <tt>allowed</tt>.
1386      *
1387      * @param allowed          allowed classifiers
1388      * @param dest             destination set
1389      * @param maybeClassifiers potential classifiers to add
1390      */

1391     private static void addClassifier(Set<String> allowed, Set<String> dest, String... maybeClassifiers) {
1392         for (String id : maybeClassifiers) {
1393             if (allowed.contains(id)) {
1394                 dest.add(id);
1395             }
1396         }
1397     }
1398
1399     private static String normalizeOsReleaseVariableValue(String value) {
1400         // Variable assignment values may be enclosed in double or single quotes.
1401         return value.trim().replaceAll("[\"']", "");
1402     }
1403
1404     private static String normalize(String value) {
1405         return value.toLowerCase(Locale.US).replaceAll("[^a-z0-9]+""");
1406     }
1407
1408     private static String normalizeArch(String value) {
1409         value = normalize(value);
1410         if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
1411             return "x86_64";
1412         }
1413         if (value.matches("^(x8632|x86|i[3-6]86|ia32|x32)$")) {
1414             return "x86_32";
1415         }
1416         if (value.matches("^(ia64|itanium64)$")) {
1417             return "itanium_64";
1418         }
1419         if (value.matches("^(sparc|sparc32)$")) {
1420             return "sparc_32";
1421         }
1422         if (value.matches("^(sparcv9|sparc64)$")) {
1423             return "sparc_64";
1424         }
1425         if (value.matches("^(arm|arm32)$")) {
1426             return "arm_32";
1427         }
1428         if ("aarch64".equals(value)) {
1429             return "aarch_64";
1430         }
1431         if (value.matches("^(ppc|ppc32)$")) {
1432             return "ppc_32";
1433         }
1434         if ("ppc64".equals(value)) {
1435             return "ppc_64";
1436         }
1437         if ("ppc64le".equals(value)) {
1438             return "ppcle_64";
1439         }
1440         if ("s390".equals(value)) {
1441             return "s390_32";
1442         }
1443         if ("s390x".equals(value)) {
1444             return "s390_64";
1445         }
1446
1447         return "unknown";
1448     }
1449
1450     private static String normalizeOs(String value) {
1451         value = normalize(value);
1452         if (value.startsWith("aix")) {
1453             return "aix";
1454         }
1455         if (value.startsWith("hpux")) {
1456             return "hpux";
1457         }
1458         if (value.startsWith("os400")) {
1459             // Avoid the names such as os4000
1460             if (value.length() <= 5 || !Character.isDigit(value.charAt(5))) {
1461                 return "os400";
1462             }
1463         }
1464         if (value.startsWith("linux")) {
1465             return "linux";
1466         }
1467         if (value.startsWith("macosx") || value.startsWith("osx")) {
1468             return "osx";
1469         }
1470         if (value.startsWith("freebsd")) {
1471             return "freebsd";
1472         }
1473         if (value.startsWith("openbsd")) {
1474             return "openbsd";
1475         }
1476         if (value.startsWith("netbsd")) {
1477             return "netbsd";
1478         }
1479         if (value.startsWith("solaris") || value.startsWith("sunos")) {
1480             return "sunos";
1481         }
1482         if (value.startsWith("windows")) {
1483             return "windows";
1484         }
1485
1486         return "unknown";
1487     }
1488
1489     private static final class AtomicLongCounter extends AtomicLong implements LongCounter {
1490         private static final long serialVersionUID = 4074772784610639305L;
1491
1492         @Override
1493         public void add(long delta) {
1494             addAndGet(delta);
1495         }
1496
1497         @Override
1498         public void increment() {
1499             incrementAndGet();
1500         }
1501
1502         @Override
1503         public void decrement() {
1504             decrementAndGet();
1505         }
1506
1507         @Override
1508         public long value() {
1509             return get();
1510         }
1511     }
1512
1513     private interface ThreadLocalRandomProvider {
1514         Random current();
1515     }
1516
1517     private PlatformDependent() {
1518         // only static method supported
1519     }
1520 }
1521