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