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