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