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