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