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