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