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