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