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