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