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 sun.misc.Unsafe;
21
22 import java.lang.reflect.Constructor;
23 import java.lang.reflect.Field;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.nio.Buffer;
27 import java.nio.ByteBuffer;
28 import java.security.AccessController;
29 import java.security.PrivilegedAction;
30 import java.util.concurrent.atomic.AtomicLong;
31
32 import static io.netty.util.internal.ObjectUtil.checkNotNull;
33
34
35
36
37 @SuppressJava6Requirement(reason = "Unsafe access is guarded")
38 final class PlatformDependent0 {
39
40 private static final InternalLogger logger = InternalLoggerFactory.getInstance(PlatformDependent0.class);
41 private static final long ADDRESS_FIELD_OFFSET;
42 private static final long BYTE_ARRAY_BASE_OFFSET;
43 private static final long INT_ARRAY_BASE_OFFSET;
44 private static final long INT_ARRAY_INDEX_SCALE;
45 private static final long LONG_ARRAY_BASE_OFFSET;
46 private static final long LONG_ARRAY_INDEX_SCALE;
47 private static final Constructor<?> DIRECT_BUFFER_CONSTRUCTOR;
48 private static final Throwable EXPLICIT_NO_UNSAFE_CAUSE = explicitNoUnsafeCause0();
49 private static final Method ALLOCATE_ARRAY_METHOD;
50 private static final Method ALIGN_SLICE;
51 private static final int JAVA_VERSION = javaVersion0();
52 private static final boolean IS_ANDROID = isAndroid0();
53 private static final boolean STORE_FENCE_AVAILABLE;
54
55 private static final Throwable UNSAFE_UNAVAILABILITY_CAUSE;
56 private static final Object INTERNAL_UNSAFE;
57
58
59
60 private static final boolean RUNNING_IN_NATIVE_IMAGE = SystemPropertyUtil.contains(
61 "org.graalvm.nativeimage.imagecode");
62
63 private static final boolean IS_EXPLICIT_TRY_REFLECTION_SET_ACCESSIBLE = explicitTryReflectionSetAccessible0();
64
65 static final Unsafe UNSAFE;
66
67
68 static final int HASH_CODE_ASCII_SEED = 0xc2b2ae35;
69 static final int HASH_CODE_C1 = 0xcc9e2d51;
70 static final int HASH_CODE_C2 = 0x1b873593;
71
72
73
74
75
76 private static final long UNSAFE_COPY_THRESHOLD = 1024L * 1024L;
77
78 private static final boolean UNALIGNED;
79
80 private static final long BITS_MAX_DIRECT_MEMORY;
81
82 static {
83 final ByteBuffer direct;
84 Field addressField = null;
85 Method allocateArrayMethod = null;
86 Throwable unsafeUnavailabilityCause = null;
87 Unsafe unsafe;
88 Object internalUnsafe = null;
89 boolean storeFenceAvailable = false;
90 if ((unsafeUnavailabilityCause = EXPLICIT_NO_UNSAFE_CAUSE) != null) {
91 direct = null;
92 addressField = null;
93 unsafe = null;
94 internalUnsafe = null;
95 } else {
96 direct = ByteBuffer.allocateDirect(1);
97
98
99 final Object maybeUnsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
100 @Override
101 public Object run() {
102 try {
103 final Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
104
105
106 Throwable cause = ReflectionUtil.trySetAccessible(unsafeField, false);
107 if (cause != null) {
108 return cause;
109 }
110
111 return unsafeField.get(null);
112 } catch (NoSuchFieldException e) {
113 return e;
114 } catch (SecurityException e) {
115 return e;
116 } catch (IllegalAccessException e) {
117 return e;
118 } catch (NoClassDefFoundError e) {
119
120
121 return e;
122 }
123 }
124 });
125
126
127
128
129
130 if (maybeUnsafe instanceof Throwable) {
131 unsafe = null;
132 unsafeUnavailabilityCause = (Throwable) maybeUnsafe;
133 if (logger.isTraceEnabled()) {
134 logger.debug("sun.misc.Unsafe.theUnsafe: unavailable", (Throwable) maybeUnsafe);
135 } else {
136 logger.debug("sun.misc.Unsafe.theUnsafe: unavailable: {}", ((Throwable) maybeUnsafe).getMessage());
137 }
138 } else {
139 unsafe = (Unsafe) maybeUnsafe;
140 logger.debug("sun.misc.Unsafe.theUnsafe: available");
141 }
142
143
144
145
146 if (unsafe != null) {
147 final Unsafe finalUnsafe = unsafe;
148 final Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
149 @Override
150 public Object run() {
151 try {
152 finalUnsafe.getClass().getDeclaredMethod(
153 "copyMemory", Object.class, long.class, Object.class, long.class, long.class);
154 return null;
155 } catch (NoSuchMethodException e) {
156 return e;
157 } catch (SecurityException e) {
158 return e;
159 }
160 }
161 });
162
163 if (maybeException == null) {
164 logger.debug("sun.misc.Unsafe.copyMemory: available");
165 } else {
166
167 unsafe = null;
168 unsafeUnavailabilityCause = (Throwable) maybeException;
169 if (logger.isTraceEnabled()) {
170 logger.debug("sun.misc.Unsafe.copyMemory: unavailable", (Throwable) maybeException);
171 } else {
172 logger.debug("sun.misc.Unsafe.copyMemory: unavailable: {}",
173 ((Throwable) maybeException).getMessage());
174 }
175 }
176 }
177
178
179 if (unsafe != null) {
180 final Unsafe finalUnsafe = unsafe;
181 final Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
182 @Override
183 public Object run() {
184 try {
185 finalUnsafe.getClass().getDeclaredMethod("storeFence");
186 return null;
187 } catch (NoSuchMethodException e) {
188 return e;
189 } catch (SecurityException e) {
190 return e;
191 }
192 }
193 });
194
195 if (maybeException == null) {
196 logger.debug("sun.misc.Unsafe.storeFence: available");
197 storeFenceAvailable = true;
198 } else {
199 storeFenceAvailable = false;
200
201 if (logger.isTraceEnabled()) {
202 logger.debug("sun.misc.Unsafe.storeFence: unavailable", (Throwable) maybeException);
203 } else {
204 logger.debug("sun.misc.Unsafe.storeFence: unavailable: {}",
205 ((Throwable) maybeException).getMessage());
206 }
207 }
208 }
209
210 if (unsafe != null) {
211 final Unsafe finalUnsafe = unsafe;
212
213
214 final Object maybeAddressField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
215 @Override
216 public Object run() {
217 try {
218 final Field field = Buffer.class.getDeclaredField("address");
219
220
221 final long offset = finalUnsafe.objectFieldOffset(field);
222 final long address = finalUnsafe.getLong(direct, offset);
223
224
225 if (address == 0) {
226 return null;
227 }
228 return field;
229 } catch (NoSuchFieldException e) {
230 return e;
231 } catch (SecurityException e) {
232 return e;
233 }
234 }
235 });
236
237 if (maybeAddressField instanceof Field) {
238 addressField = (Field) maybeAddressField;
239 logger.debug("java.nio.Buffer.address: available");
240 } else {
241 unsafeUnavailabilityCause = (Throwable) maybeAddressField;
242 if (logger.isTraceEnabled()) {
243 logger.debug("java.nio.Buffer.address: unavailable", (Throwable) maybeAddressField);
244 } else {
245 logger.debug("java.nio.Buffer.address: unavailable: {}",
246 ((Throwable) maybeAddressField).getMessage());
247 }
248
249
250
251 unsafe = null;
252 }
253 }
254
255 if (unsafe != null) {
256
257
258 long byteArrayIndexScale = unsafe.arrayIndexScale(byte[].class);
259 if (byteArrayIndexScale != 1) {
260 logger.debug("unsafe.arrayIndexScale is {} (expected: 1). Not using unsafe.", byteArrayIndexScale);
261 unsafeUnavailabilityCause = new UnsupportedOperationException("Unexpected unsafe.arrayIndexScale");
262 unsafe = null;
263 }
264 }
265 }
266 UNSAFE_UNAVAILABILITY_CAUSE = unsafeUnavailabilityCause;
267 UNSAFE = unsafe;
268
269 if (unsafe == null) {
270 ADDRESS_FIELD_OFFSET = -1;
271 BYTE_ARRAY_BASE_OFFSET = -1;
272 LONG_ARRAY_BASE_OFFSET = -1;
273 LONG_ARRAY_INDEX_SCALE = -1;
274 INT_ARRAY_BASE_OFFSET = -1;
275 INT_ARRAY_INDEX_SCALE = -1;
276 UNALIGNED = false;
277 BITS_MAX_DIRECT_MEMORY = -1;
278 DIRECT_BUFFER_CONSTRUCTOR = null;
279 ALLOCATE_ARRAY_METHOD = null;
280 STORE_FENCE_AVAILABLE = false;
281 } else {
282 Constructor<?> directBufferConstructor;
283 long address = -1;
284 try {
285 final Object maybeDirectBufferConstructor =
286 AccessController.doPrivileged(new PrivilegedAction<Object>() {
287 @Override
288 public Object run() {
289 try {
290 final Constructor<?> constructor = javaVersion() >= 21 ?
291 direct.getClass().getDeclaredConstructor(long.class, long.class) :
292 direct.getClass().getDeclaredConstructor(long.class, int.class);
293 Throwable cause = ReflectionUtil.trySetAccessible(constructor, true);
294 if (cause != null) {
295 return cause;
296 }
297 return constructor;
298 } catch (NoSuchMethodException e) {
299 return e;
300 } catch (SecurityException e) {
301 return e;
302 }
303 }
304 });
305
306 if (maybeDirectBufferConstructor instanceof Constructor<?>) {
307 address = UNSAFE.allocateMemory(1);
308
309 try {
310 ((Constructor<?>) maybeDirectBufferConstructor).newInstance(address, 1);
311 directBufferConstructor = (Constructor<?>) maybeDirectBufferConstructor;
312 logger.debug("direct buffer constructor: available");
313 } catch (InstantiationException e) {
314 directBufferConstructor = null;
315 } catch (IllegalAccessException e) {
316 directBufferConstructor = null;
317 } catch (InvocationTargetException e) {
318 directBufferConstructor = null;
319 }
320 } else {
321 if (logger.isTraceEnabled()) {
322 logger.debug("direct buffer constructor: unavailable",
323 (Throwable) maybeDirectBufferConstructor);
324 } else {
325 logger.debug("direct buffer constructor: unavailable: {}",
326 ((Throwable) maybeDirectBufferConstructor).getMessage());
327 }
328 directBufferConstructor = null;
329 }
330 } finally {
331 if (address != -1) {
332 UNSAFE.freeMemory(address);
333 }
334 }
335 DIRECT_BUFFER_CONSTRUCTOR = directBufferConstructor;
336 ADDRESS_FIELD_OFFSET = objectFieldOffset(addressField);
337 BYTE_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(byte[].class);
338 INT_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(int[].class);
339 INT_ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale(int[].class);
340 LONG_ARRAY_BASE_OFFSET = UNSAFE.arrayBaseOffset(long[].class);
341 LONG_ARRAY_INDEX_SCALE = UNSAFE.arrayIndexScale(long[].class);
342 final boolean unaligned;
343
344 final AtomicLong maybeMaxMemory = new AtomicLong(-1);
345 Object maybeUnaligned = AccessController.doPrivileged(new PrivilegedAction<Object>() {
346 @Override
347 public Object run() {
348 try {
349 Class<?> bitsClass =
350 Class.forName("java.nio.Bits", false, getSystemClassLoader());
351 int version = javaVersion();
352 if (unsafeStaticFieldOffsetSupported() && version >= 9) {
353
354 String fieldName = version >= 11? "MAX_MEMORY" : "maxMemory";
355
356
357 try {
358 Field maxMemoryField = bitsClass.getDeclaredField(fieldName);
359 if (maxMemoryField.getType() == long.class) {
360 long offset = UNSAFE.staticFieldOffset(maxMemoryField);
361 Object object = UNSAFE.staticFieldBase(maxMemoryField);
362 maybeMaxMemory.lazySet(UNSAFE.getLong(object, offset));
363 }
364 } catch (Throwable ignore) {
365
366 }
367 fieldName = version >= 11? "UNALIGNED" : "unaligned";
368 try {
369 Field unalignedField = bitsClass.getDeclaredField(fieldName);
370 if (unalignedField.getType() == boolean.class) {
371 long offset = UNSAFE.staticFieldOffset(unalignedField);
372 Object object = UNSAFE.staticFieldBase(unalignedField);
373 return UNSAFE.getBoolean(object, offset);
374 }
375
376
377 } catch (NoSuchFieldException ignore) {
378
379 }
380 }
381 Method unalignedMethod = bitsClass.getDeclaredMethod("unaligned");
382 Throwable cause = ReflectionUtil.trySetAccessible(unalignedMethod, true);
383 if (cause != null) {
384 return cause;
385 }
386 return unalignedMethod.invoke(null);
387 } catch (NoSuchMethodException e) {
388 return e;
389 } catch (SecurityException e) {
390 return e;
391 } catch (IllegalAccessException e) {
392 return e;
393 } catch (ClassNotFoundException e) {
394 return e;
395 } catch (InvocationTargetException e) {
396 return e;
397 }
398 }
399 });
400
401 if (maybeUnaligned instanceof Boolean) {
402 unaligned = (Boolean) maybeUnaligned;
403 logger.debug("java.nio.Bits.unaligned: available, {}", unaligned);
404 } else {
405 String arch = SystemPropertyUtil.get("os.arch", "");
406
407 unaligned = arch.matches("^(i[3-6]86|x86(_64)?|x64|amd64)$");
408 Throwable t = (Throwable) maybeUnaligned;
409 if (logger.isTraceEnabled()) {
410 logger.debug("java.nio.Bits.unaligned: unavailable, {}", unaligned, t);
411 } else {
412 logger.debug("java.nio.Bits.unaligned: unavailable, {}, {}", unaligned, t.getMessage());
413 }
414 }
415
416 UNALIGNED = unaligned;
417 BITS_MAX_DIRECT_MEMORY = maybeMaxMemory.get() >= 0? maybeMaxMemory.get() : -1;
418
419 if (javaVersion() >= 9) {
420 Object maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
421 @Override
422 public Object run() {
423 try {
424
425
426 Class<?> internalUnsafeClass = getClassLoader(PlatformDependent0.class)
427 .loadClass("jdk.internal.misc.Unsafe");
428 Method method = internalUnsafeClass.getDeclaredMethod("getUnsafe");
429 return method.invoke(null);
430 } catch (Throwable e) {
431 return e;
432 }
433 }
434 });
435 if (!(maybeException instanceof Throwable)) {
436 internalUnsafe = maybeException;
437 final Object finalInternalUnsafe = internalUnsafe;
438 maybeException = AccessController.doPrivileged(new PrivilegedAction<Object>() {
439 @Override
440 public Object run() {
441 try {
442 return finalInternalUnsafe.getClass().getDeclaredMethod(
443 "allocateUninitializedArray", Class.class, int.class);
444 } catch (NoSuchMethodException e) {
445 return e;
446 } catch (SecurityException e) {
447 return e;
448 }
449 }
450 });
451
452 if (maybeException instanceof Method) {
453 try {
454 Method m = (Method) maybeException;
455 byte[] bytes = (byte[]) m.invoke(finalInternalUnsafe, byte.class, 8);
456 assert bytes.length == 8;
457 allocateArrayMethod = m;
458 } catch (IllegalAccessException e) {
459 maybeException = e;
460 } catch (InvocationTargetException e) {
461 maybeException = e;
462 }
463 }
464 }
465
466 if (maybeException instanceof Throwable) {
467 if (logger.isTraceEnabled()) {
468 logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable",
469 (Throwable) maybeException);
470 } else {
471 logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable: {}",
472 ((Throwable) maybeException).getMessage());
473 }
474 } else {
475 logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): available");
476 }
477 } else {
478 logger.debug("jdk.internal.misc.Unsafe.allocateUninitializedArray(int): unavailable prior to Java9");
479 }
480 ALLOCATE_ARRAY_METHOD = allocateArrayMethod;
481 STORE_FENCE_AVAILABLE = storeFenceAvailable;
482 }
483
484 if (javaVersion() > 9) {
485 ALIGN_SLICE = (Method) AccessController.doPrivileged(new PrivilegedAction<Object>() {
486 @Override
487 public Object run() {
488 try {
489 return ByteBuffer.class.getDeclaredMethod("alignedSlice", int.class);
490 } catch (Exception e) {
491 return null;
492 }
493 }
494 });
495 } else {
496 ALIGN_SLICE = null;
497 }
498
499 INTERNAL_UNSAFE = internalUnsafe;
500
501 logger.debug("java.nio.DirectByteBuffer.<init>(long, {int,long}): {}",
502 DIRECT_BUFFER_CONSTRUCTOR != null ? "available" : "unavailable");
503 }
504
505 private static boolean unsafeStaticFieldOffsetSupported() {
506 return !RUNNING_IN_NATIVE_IMAGE;
507 }
508
509 static boolean isExplicitNoUnsafe() {
510 return EXPLICIT_NO_UNSAFE_CAUSE != null;
511 }
512
513 private static Throwable explicitNoUnsafeCause0() {
514 final boolean noUnsafe = SystemPropertyUtil.getBoolean("io.netty.noUnsafe", false);
515 logger.debug("-Dio.netty.noUnsafe: {}", noUnsafe);
516
517 if (noUnsafe) {
518 logger.debug("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)");
519 return new UnsupportedOperationException("sun.misc.Unsafe: unavailable (io.netty.noUnsafe)");
520 }
521
522
523 String unsafePropName;
524 if (SystemPropertyUtil.contains("io.netty.tryUnsafe")) {
525 unsafePropName = "io.netty.tryUnsafe";
526 } else {
527 unsafePropName = "org.jboss.netty.tryUnsafe";
528 }
529
530 if (!SystemPropertyUtil.getBoolean(unsafePropName, true)) {
531 String msg = "sun.misc.Unsafe: unavailable (" + unsafePropName + ")";
532 logger.debug(msg);
533 return new UnsupportedOperationException(msg);
534 }
535
536 return null;
537 }
538
539 static boolean isUnaligned() {
540 return UNALIGNED;
541 }
542
543
544
545
546 static long bitsMaxDirectMemory() {
547 return BITS_MAX_DIRECT_MEMORY;
548 }
549
550 static boolean hasUnsafe() {
551 return UNSAFE != null;
552 }
553
554 static Throwable getUnsafeUnavailabilityCause() {
555 return UNSAFE_UNAVAILABILITY_CAUSE;
556 }
557
558 static boolean unalignedAccess() {
559 return UNALIGNED;
560 }
561
562 static void throwException(Throwable cause) {
563
564 UNSAFE.throwException(checkNotNull(cause, "cause"));
565 }
566
567 static boolean hasDirectBufferNoCleanerConstructor() {
568 return DIRECT_BUFFER_CONSTRUCTOR != null;
569 }
570
571 static ByteBuffer reallocateDirectNoCleaner(ByteBuffer buffer, int capacity) {
572 return newDirectBuffer(UNSAFE.reallocateMemory(directBufferAddress(buffer), capacity), capacity);
573 }
574
575 static ByteBuffer allocateDirectNoCleaner(int capacity) {
576
577
578
579 return newDirectBuffer(UNSAFE.allocateMemory(Math.max(1, capacity)), capacity);
580 }
581
582 static boolean hasAlignSliceMethod() {
583 return ALIGN_SLICE != null;
584 }
585
586 static ByteBuffer alignSlice(ByteBuffer buffer, int alignment) {
587 try {
588 return (ByteBuffer) ALIGN_SLICE.invoke(buffer, alignment);
589 } catch (IllegalAccessException e) {
590 throw new Error(e);
591 } catch (InvocationTargetException e) {
592 throw new Error(e);
593 }
594 }
595
596 static boolean hasAllocateArrayMethod() {
597 return ALLOCATE_ARRAY_METHOD != null;
598 }
599
600 static byte[] allocateUninitializedArray(int size) {
601 try {
602 return (byte[]) ALLOCATE_ARRAY_METHOD.invoke(INTERNAL_UNSAFE, byte.class, size);
603 } catch (IllegalAccessException e) {
604 throw new Error(e);
605 } catch (InvocationTargetException e) {
606 throw new Error(e);
607 }
608 }
609
610 static ByteBuffer newDirectBuffer(long address, int capacity) {
611 ObjectUtil.checkPositiveOrZero(capacity, "capacity");
612
613 try {
614 return (ByteBuffer) DIRECT_BUFFER_CONSTRUCTOR.newInstance(address, capacity);
615 } catch (Throwable cause) {
616
617 if (cause instanceof Error) {
618 throw (Error) cause;
619 }
620 throw new Error(cause);
621 }
622 }
623
624 static long directBufferAddress(ByteBuffer buffer) {
625 return getLong(buffer, ADDRESS_FIELD_OFFSET);
626 }
627
628 static long byteArrayBaseOffset() {
629 return BYTE_ARRAY_BASE_OFFSET;
630 }
631
632 static Object getObject(Object object, long fieldOffset) {
633 return UNSAFE.getObject(object, fieldOffset);
634 }
635
636 static int getInt(Object object, long fieldOffset) {
637 return UNSAFE.getInt(object, fieldOffset);
638 }
639
640 static void safeConstructPutInt(Object object, long fieldOffset, int value) {
641 if (STORE_FENCE_AVAILABLE) {
642 UNSAFE.putInt(object, fieldOffset, value);
643 UNSAFE.storeFence();
644 } else {
645 UNSAFE.putIntVolatile(object, fieldOffset, value);
646 }
647 }
648
649 private static long getLong(Object object, long fieldOffset) {
650 return UNSAFE.getLong(object, fieldOffset);
651 }
652
653 static long objectFieldOffset(Field field) {
654 return UNSAFE.objectFieldOffset(field);
655 }
656
657 static byte getByte(long address) {
658 return UNSAFE.getByte(address);
659 }
660
661 static short getShort(long address) {
662 return UNSAFE.getShort(address);
663 }
664
665 static int getInt(long address) {
666 return UNSAFE.getInt(address);
667 }
668
669 static long getLong(long address) {
670 return UNSAFE.getLong(address);
671 }
672
673 static byte getByte(byte[] data, int index) {
674 return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
675 }
676
677 static byte getByte(byte[] data, long index) {
678 return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
679 }
680
681 static short getShort(byte[] data, int index) {
682 return UNSAFE.getShort(data, BYTE_ARRAY_BASE_OFFSET + index);
683 }
684
685 static int getInt(byte[] data, int index) {
686 return UNSAFE.getInt(data, BYTE_ARRAY_BASE_OFFSET + index);
687 }
688
689 static int getInt(int[] data, long index) {
690 return UNSAFE.getInt(data, INT_ARRAY_BASE_OFFSET + INT_ARRAY_INDEX_SCALE * index);
691 }
692
693 static int getIntVolatile(long address) {
694 return UNSAFE.getIntVolatile(null, address);
695 }
696
697 static void putIntOrdered(long adddress, int newValue) {
698 UNSAFE.putOrderedInt(null, adddress, newValue);
699 }
700
701 static long getLong(byte[] data, int index) {
702 return UNSAFE.getLong(data, BYTE_ARRAY_BASE_OFFSET + index);
703 }
704
705 static long getLong(long[] data, long index) {
706 return UNSAFE.getLong(data, LONG_ARRAY_BASE_OFFSET + LONG_ARRAY_INDEX_SCALE * index);
707 }
708
709 static void putByte(long address, byte value) {
710 UNSAFE.putByte(address, value);
711 }
712
713 static void putShort(long address, short value) {
714 UNSAFE.putShort(address, value);
715 }
716
717 static void putInt(long address, int value) {
718 UNSAFE.putInt(address, value);
719 }
720
721 static void putLong(long address, long value) {
722 UNSAFE.putLong(address, value);
723 }
724
725 static void putByte(byte[] data, int index, byte value) {
726 UNSAFE.putByte(data, BYTE_ARRAY_BASE_OFFSET + index, value);
727 }
728
729 static void putByte(Object data, long offset, byte value) {
730 UNSAFE.putByte(data, offset, value);
731 }
732
733 static void putShort(byte[] data, int index, short value) {
734 UNSAFE.putShort(data, BYTE_ARRAY_BASE_OFFSET + index, value);
735 }
736
737 static void putInt(byte[] data, int index, int value) {
738 UNSAFE.putInt(data, BYTE_ARRAY_BASE_OFFSET + index, value);
739 }
740
741 static void putLong(byte[] data, int index, long value) {
742 UNSAFE.putLong(data, BYTE_ARRAY_BASE_OFFSET + index, value);
743 }
744
745 static void putObject(Object o, long offset, Object x) {
746 UNSAFE.putObject(o, offset, x);
747 }
748
749 static void copyMemory(long srcAddr, long dstAddr, long length) {
750
751
752 if (javaVersion() <= 8) {
753 copyMemoryWithSafePointPolling(srcAddr, dstAddr, length);
754 } else {
755 UNSAFE.copyMemory(srcAddr, dstAddr, length);
756 }
757 }
758
759 private static void copyMemoryWithSafePointPolling(long srcAddr, long dstAddr, long length) {
760 while (length > 0) {
761 long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
762 UNSAFE.copyMemory(srcAddr, dstAddr, size);
763 length -= size;
764 srcAddr += size;
765 dstAddr += size;
766 }
767 }
768
769 static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
770
771
772 if (javaVersion() <= 8) {
773 copyMemoryWithSafePointPolling(src, srcOffset, dst, dstOffset, length);
774 } else {
775 UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
776 }
777 }
778
779 private static void copyMemoryWithSafePointPolling(
780 Object src, long srcOffset, Object dst, long dstOffset, long length) {
781 while (length > 0) {
782 long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
783 UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
784 length -= size;
785 srcOffset += size;
786 dstOffset += size;
787 }
788 }
789
790 static void setMemory(long address, long bytes, byte value) {
791 UNSAFE.setMemory(address, bytes, value);
792 }
793
794 static void setMemory(Object o, long offset, long bytes, byte value) {
795 UNSAFE.setMemory(o, offset, bytes, value);
796 }
797
798 static boolean equals(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
799 int remainingBytes = length & 7;
800 final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
801 final long diff = startPos2 - startPos1;
802 if (length >= 8) {
803 final long end = baseOffset1 + remainingBytes;
804 for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
805 if (UNSAFE.getLong(bytes1, i) != UNSAFE.getLong(bytes2, i + diff)) {
806 return false;
807 }
808 }
809 }
810 if (remainingBytes >= 4) {
811 remainingBytes -= 4;
812 long pos = baseOffset1 + remainingBytes;
813 if (UNSAFE.getInt(bytes1, pos) != UNSAFE.getInt(bytes2, pos + diff)) {
814 return false;
815 }
816 }
817 final long baseOffset2 = baseOffset1 + diff;
818 if (remainingBytes >= 2) {
819 return UNSAFE.getChar(bytes1, baseOffset1) == UNSAFE.getChar(bytes2, baseOffset2) &&
820 (remainingBytes == 2 ||
821 UNSAFE.getByte(bytes1, baseOffset1 + 2) == UNSAFE.getByte(bytes2, baseOffset2 + 2));
822 }
823 return remainingBytes == 0 ||
824 UNSAFE.getByte(bytes1, baseOffset1) == UNSAFE.getByte(bytes2, baseOffset2);
825 }
826
827 static int equalsConstantTime(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
828 long result = 0;
829 long remainingBytes = length & 7;
830 final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
831 final long end = baseOffset1 + remainingBytes;
832 final long diff = startPos2 - startPos1;
833 for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
834 result |= UNSAFE.getLong(bytes1, i) ^ UNSAFE.getLong(bytes2, i + diff);
835 }
836 if (remainingBytes >= 4) {
837 result |= UNSAFE.getInt(bytes1, baseOffset1) ^ UNSAFE.getInt(bytes2, baseOffset1 + diff);
838 remainingBytes -= 4;
839 }
840 if (remainingBytes >= 2) {
841 long pos = end - remainingBytes;
842 result |= UNSAFE.getChar(bytes1, pos) ^ UNSAFE.getChar(bytes2, pos + diff);
843 remainingBytes -= 2;
844 }
845 if (remainingBytes == 1) {
846 long pos = end - 1;
847 result |= UNSAFE.getByte(bytes1, pos) ^ UNSAFE.getByte(bytes2, pos + diff);
848 }
849 return ConstantTimeUtils.equalsConstantTime(result, 0);
850 }
851
852 static boolean isZero(byte[] bytes, int startPos, int length) {
853 if (length <= 0) {
854 return true;
855 }
856 final long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
857 int remainingBytes = length & 7;
858 final long end = baseOffset + remainingBytes;
859 for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
860 if (UNSAFE.getLong(bytes, i) != 0) {
861 return false;
862 }
863 }
864
865 if (remainingBytes >= 4) {
866 remainingBytes -= 4;
867 if (UNSAFE.getInt(bytes, baseOffset + remainingBytes) != 0) {
868 return false;
869 }
870 }
871 if (remainingBytes >= 2) {
872 return UNSAFE.getChar(bytes, baseOffset) == 0 &&
873 (remainingBytes == 2 || bytes[startPos + 2] == 0);
874 }
875 return bytes[startPos] == 0;
876 }
877
878 static int hashCodeAscii(byte[] bytes, int startPos, int length) {
879 int hash = HASH_CODE_ASCII_SEED;
880 long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
881 final int remainingBytes = length & 7;
882 final long end = baseOffset + remainingBytes;
883 for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
884 hash = hashCodeAsciiCompute(UNSAFE.getLong(bytes, i), hash);
885 }
886 if (remainingBytes == 0) {
887 return hash;
888 }
889 int hcConst = HASH_CODE_C1;
890 if (remainingBytes != 2 & remainingBytes != 4 & remainingBytes != 6) {
891 hash = hash * HASH_CODE_C1 + hashCodeAsciiSanitize(UNSAFE.getByte(bytes, baseOffset));
892 hcConst = HASH_CODE_C2;
893 baseOffset++;
894 }
895 if (remainingBytes != 1 & remainingBytes != 4 & remainingBytes != 5) {
896 hash = hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getShort(bytes, baseOffset));
897 hcConst = hcConst == HASH_CODE_C1 ? HASH_CODE_C2 : HASH_CODE_C1;
898 baseOffset += 2;
899 }
900 if (remainingBytes >= 4) {
901 return hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getInt(bytes, baseOffset));
902 }
903 return hash;
904 }
905
906 static int hashCodeAsciiCompute(long value, int hash) {
907
908
909 return hash * HASH_CODE_C1 +
910
911 hashCodeAsciiSanitize((int) value) * HASH_CODE_C2 +
912
913 (int) ((value & 0x1f1f1f1f00000000L) >>> 32);
914 }
915
916 static int hashCodeAsciiSanitize(int value) {
917 return value & 0x1f1f1f1f;
918 }
919
920 static int hashCodeAsciiSanitize(short value) {
921 return value & 0x1f1f;
922 }
923
924 static int hashCodeAsciiSanitize(byte value) {
925 return value & 0x1f;
926 }
927
928 static ClassLoader getClassLoader(final Class<?> clazz) {
929 if (System.getSecurityManager() == null) {
930 return clazz.getClassLoader();
931 } else {
932 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
933 @Override
934 public ClassLoader run() {
935 return clazz.getClassLoader();
936 }
937 });
938 }
939 }
940
941 static ClassLoader getContextClassLoader() {
942 if (System.getSecurityManager() == null) {
943 return Thread.currentThread().getContextClassLoader();
944 } else {
945 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
946 @Override
947 public ClassLoader run() {
948 return Thread.currentThread().getContextClassLoader();
949 }
950 });
951 }
952 }
953
954 static ClassLoader getSystemClassLoader() {
955 if (System.getSecurityManager() == null) {
956 return ClassLoader.getSystemClassLoader();
957 } else {
958 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
959 @Override
960 public ClassLoader run() {
961 return ClassLoader.getSystemClassLoader();
962 }
963 });
964 }
965 }
966
967 static int addressSize() {
968 return UNSAFE.addressSize();
969 }
970
971 static long allocateMemory(long size) {
972 return UNSAFE.allocateMemory(size);
973 }
974
975 static void freeMemory(long address) {
976 UNSAFE.freeMemory(address);
977 }
978
979 static long reallocateMemory(long address, long newSize) {
980 return UNSAFE.reallocateMemory(address, newSize);
981 }
982
983 static boolean isAndroid() {
984 return IS_ANDROID;
985 }
986
987 private static boolean isAndroid0() {
988
989
990
991
992
993
994
995 String vmName = SystemPropertyUtil.get("java.vm.name");
996 boolean isAndroid = "Dalvik".equals(vmName);
997 if (isAndroid) {
998 logger.debug("Platform: Android");
999 }
1000 return isAndroid;
1001 }
1002
1003 private static boolean explicitTryReflectionSetAccessible0() {
1004
1005 return SystemPropertyUtil.getBoolean("io.netty.tryReflectionSetAccessible",
1006 javaVersion() < 9 || RUNNING_IN_NATIVE_IMAGE);
1007 }
1008
1009 static boolean isExplicitTryReflectionSetAccessible() {
1010 return IS_EXPLICIT_TRY_REFLECTION_SET_ACCESSIBLE;
1011 }
1012
1013 static int javaVersion() {
1014 return JAVA_VERSION;
1015 }
1016
1017 private static int javaVersion0() {
1018 final int majorVersion;
1019
1020 if (isAndroid0()) {
1021 majorVersion = 6;
1022 } else {
1023 majorVersion = majorVersionFromJavaSpecificationVersion();
1024 }
1025
1026 logger.debug("Java version: {}", majorVersion);
1027
1028 return majorVersion;
1029 }
1030
1031
1032 static int majorVersionFromJavaSpecificationVersion() {
1033 return majorVersion(SystemPropertyUtil.get("java.specification.version", "1.6"));
1034 }
1035
1036
1037 static int majorVersion(final String javaSpecVersion) {
1038 final String[] components = javaSpecVersion.split("\\.");
1039 final int[] version = new int[components.length];
1040 for (int i = 0; i < components.length; i++) {
1041 version[i] = Integer.parseInt(components[i]);
1042 }
1043
1044 if (version[0] == 1) {
1045 assert version[1] >= 6;
1046 return version[1];
1047 } else {
1048 return version[0];
1049 }
1050 }
1051
1052 private PlatformDependent0() {
1053 }
1054 }