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