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