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