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