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 (unsafeStaticFieldOffsetSupported() && 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 private static boolean unsafeStaticFieldOffsetSupported() {
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 String reason = "io.netty.noUnsafe";
538 String unspecified = "<unspecified>";
539 String unsafeMemoryAccess = SystemPropertyUtil.get("sun.misc.unsafe.memory.access", unspecified);
540 if (!explicitProperty && unspecified.equals(unsafeMemoryAccess) && javaVersion() >= 24) {
541 reason = "io.netty.noUnsafe=true by default on Java 24+";
542 noUnsafe = true;
543 } else if (!("allow".equals(unsafeMemoryAccess) || unspecified.equals(unsafeMemoryAccess))) {
544 reason = "--sun-misc-unsafe-memory-access=" + unsafeMemoryAccess;
545 noUnsafe = true;
546 }
547
548 if (noUnsafe) {
549 String msg = "sun.misc.Unsafe: unavailable (" + reason + ')';
550 logger.debug(msg);
551 return new UnsupportedOperationException(msg);
552 }
553
554
555 String unsafePropName;
556 if (SystemPropertyUtil.contains("io.netty.tryUnsafe")) {
557 unsafePropName = "io.netty.tryUnsafe";
558 } else {
559 unsafePropName = "org.jboss.netty.tryUnsafe";
560 }
561
562 if (!SystemPropertyUtil.getBoolean(unsafePropName, true)) {
563 String msg = "sun.misc.Unsafe: unavailable (" + unsafePropName + ')';
564 logger.debug(msg);
565 return new UnsupportedOperationException(msg);
566 }
567
568 return null;
569 }
570
571 static boolean isUnaligned() {
572 return UNALIGNED;
573 }
574
575
576
577
578 static long bitsMaxDirectMemory() {
579 return BITS_MAX_DIRECT_MEMORY;
580 }
581
582 static boolean hasUnsafe() {
583 return UNSAFE != null;
584 }
585
586 static Throwable getUnsafeUnavailabilityCause() {
587 return UNSAFE_UNAVAILABILITY_CAUSE;
588 }
589
590 static boolean unalignedAccess() {
591 return UNALIGNED;
592 }
593
594 static void throwException(Throwable cause) {
595 throwException0(cause);
596 }
597
598 @SuppressWarnings("unchecked")
599 private static <E extends Throwable> void throwException0(Throwable t) throws E {
600 throw (E) t;
601 }
602
603 static boolean hasDirectBufferNoCleanerConstructor() {
604 return DIRECT_BUFFER_CONSTRUCTOR != null;
605 }
606
607 static ByteBuffer reallocateDirectNoCleaner(ByteBuffer buffer, int capacity) {
608 return newDirectBuffer(UNSAFE.reallocateMemory(directBufferAddress(buffer), capacity), capacity);
609 }
610
611 static ByteBuffer allocateDirectNoCleaner(int capacity) {
612
613
614
615 return newDirectBuffer(UNSAFE.allocateMemory(Math.max(1, capacity)), capacity);
616 }
617
618 static boolean hasAlignSliceMethod() {
619 return ALIGN_SLICE != null;
620 }
621
622 static ByteBuffer alignSlice(ByteBuffer buffer, int alignment) {
623 try {
624 return (ByteBuffer) ALIGN_SLICE.invokeExact(buffer, alignment);
625 } catch (Throwable e) {
626 rethrowIfPossible(e);
627 throw new LinkageError("ByteBuffer.alignedSlice not available", e);
628 }
629 }
630
631 static boolean hasAllocateArrayMethod() {
632 return ALLOCATE_ARRAY_METHOD != null;
633 }
634
635 static byte[] allocateUninitializedArray(int size) {
636 try {
637 return (byte[]) (Object) ALLOCATE_ARRAY_METHOD.invokeExact(byte.class, size);
638 } catch (Throwable e) {
639 rethrowIfPossible(e);
640 throw new LinkageError("Unsafe.allocateUninitializedArray not available", e);
641 }
642 }
643
644 static ByteBuffer newDirectBuffer(long address, int capacity) {
645 ObjectUtil.checkPositiveOrZero(capacity, "capacity");
646
647 try {
648 return (ByteBuffer) DIRECT_BUFFER_CONSTRUCTOR.invokeExact(address, capacity);
649 } catch (Throwable cause) {
650 rethrowIfPossible(cause);
651 throw new LinkageError("DirectByteBuffer constructor not available", cause);
652 }
653 }
654
655 private static void rethrowIfPossible(Throwable cause) {
656 if (cause instanceof Error) {
657 throw (Error) cause;
658 }
659 if (cause instanceof RuntimeException) {
660 throw (RuntimeException) cause;
661 }
662 }
663
664 static long directBufferAddress(ByteBuffer buffer) {
665 return getLong(buffer, ADDRESS_FIELD_OFFSET);
666 }
667
668 static long byteArrayBaseOffset() {
669 return BYTE_ARRAY_BASE_OFFSET;
670 }
671
672 static Object getObject(Object object, long fieldOffset) {
673 return UNSAFE.getObject(object, fieldOffset);
674 }
675
676 static int getInt(Object object, long fieldOffset) {
677 return UNSAFE.getInt(object, fieldOffset);
678 }
679
680 static void safeConstructPutInt(Object object, long fieldOffset, int value) {
681 UNSAFE.putInt(object, fieldOffset, value);
682 UNSAFE.storeFence();
683 }
684
685 private static long getLong(Object object, long fieldOffset) {
686 return UNSAFE.getLong(object, fieldOffset);
687 }
688
689 static long objectFieldOffset(Field field) {
690 return UNSAFE.objectFieldOffset(field);
691 }
692
693 static byte getByte(long address) {
694 return UNSAFE.getByte(address);
695 }
696
697 static short getShort(long address) {
698 return UNSAFE.getShort(address);
699 }
700
701 static int getInt(long address) {
702 return UNSAFE.getInt(address);
703 }
704
705 static long getLong(long address) {
706 return UNSAFE.getLong(address);
707 }
708
709 static byte getByte(byte[] data, int index) {
710 return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
711 }
712
713 static byte getByte(byte[] data, long index) {
714 return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
715 }
716
717 static short getShort(byte[] data, int index) {
718 return UNSAFE.getShort(data, BYTE_ARRAY_BASE_OFFSET + index);
719 }
720
721 static int getInt(byte[] data, int index) {
722 return UNSAFE.getInt(data, BYTE_ARRAY_BASE_OFFSET + index);
723 }
724
725 static int getInt(int[] data, long index) {
726 return UNSAFE.getInt(data, INT_ARRAY_BASE_OFFSET + INT_ARRAY_INDEX_SCALE * index);
727 }
728
729 static int getIntVolatile(long address) {
730 return UNSAFE.getIntVolatile(null, address);
731 }
732
733 static void putIntOrdered(long address, int newValue) {
734 UNSAFE.putOrderedInt(null, address, newValue);
735 }
736
737 static long getLong(byte[] data, int index) {
738 return UNSAFE.getLong(data, BYTE_ARRAY_BASE_OFFSET + index);
739 }
740
741 static long getLong(long[] data, long index) {
742 return UNSAFE.getLong(data, LONG_ARRAY_BASE_OFFSET + LONG_ARRAY_INDEX_SCALE * index);
743 }
744
745 static void putByte(long address, byte value) {
746 UNSAFE.putByte(address, value);
747 }
748
749 static void putShort(long address, short value) {
750 UNSAFE.putShort(address, value);
751 }
752
753 static void putShortOrdered(long address, short newValue) {
754 UNSAFE.storeFence();
755 UNSAFE.putShort(null, address, newValue);
756 }
757
758 static void putInt(long address, int value) {
759 UNSAFE.putInt(address, value);
760 }
761
762 static void putLong(long address, long value) {
763 UNSAFE.putLong(address, value);
764 }
765
766 static void putByte(byte[] data, int index, byte value) {
767 UNSAFE.putByte(data, BYTE_ARRAY_BASE_OFFSET + index, value);
768 }
769
770 static void putByte(Object data, long offset, byte value) {
771 UNSAFE.putByte(data, offset, value);
772 }
773
774 static void putShort(byte[] data, int index, short value) {
775 UNSAFE.putShort(data, BYTE_ARRAY_BASE_OFFSET + index, value);
776 }
777
778 static void putInt(byte[] data, int index, int value) {
779 UNSAFE.putInt(data, BYTE_ARRAY_BASE_OFFSET + index, value);
780 }
781
782 static void putLong(byte[] data, int index, long value) {
783 UNSAFE.putLong(data, BYTE_ARRAY_BASE_OFFSET + index, value);
784 }
785
786 static void putObject(Object o, long offset, Object x) {
787 UNSAFE.putObject(o, offset, x);
788 }
789
790 static void copyMemory(long srcAddr, long dstAddr, long length) {
791
792
793 if (javaVersion() <= 8) {
794 copyMemoryWithSafePointPolling(srcAddr, dstAddr, length);
795 } else {
796 UNSAFE.copyMemory(srcAddr, dstAddr, length);
797 }
798 }
799
800 private static void copyMemoryWithSafePointPolling(long srcAddr, long dstAddr, long length) {
801 while (length > 0) {
802 long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
803 UNSAFE.copyMemory(srcAddr, dstAddr, size);
804 length -= size;
805 srcAddr += size;
806 dstAddr += size;
807 }
808 }
809
810 static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
811
812
813 if (javaVersion() <= 8) {
814 copyMemoryWithSafePointPolling(src, srcOffset, dst, dstOffset, length);
815 } else {
816 UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
817 }
818 }
819
820 private static void copyMemoryWithSafePointPolling(
821 Object src, long srcOffset, Object dst, long dstOffset, long length) {
822 while (length > 0) {
823 long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
824 UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
825 length -= size;
826 srcOffset += size;
827 dstOffset += size;
828 }
829 }
830
831 static void setMemory(long address, long bytes, byte value) {
832 UNSAFE.setMemory(address, bytes, value);
833 }
834
835 static void setMemory(Object o, long offset, long bytes, byte value) {
836 UNSAFE.setMemory(o, offset, bytes, value);
837 }
838
839 static boolean equals(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
840 int remainingBytes = length & 7;
841 final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
842 final long diff = startPos2 - startPos1;
843 if (length >= 8) {
844 final long end = baseOffset1 + remainingBytes;
845 for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
846 if (UNSAFE.getLong(bytes1, i) != UNSAFE.getLong(bytes2, i + diff)) {
847 return false;
848 }
849 }
850 }
851 if (remainingBytes >= 4) {
852 remainingBytes -= 4;
853 long pos = baseOffset1 + remainingBytes;
854 if (UNSAFE.getInt(bytes1, pos) != UNSAFE.getInt(bytes2, pos + diff)) {
855 return false;
856 }
857 }
858 final long baseOffset2 = baseOffset1 + diff;
859 if (remainingBytes >= 2) {
860 return UNSAFE.getChar(bytes1, baseOffset1) == UNSAFE.getChar(bytes2, baseOffset2) &&
861 (remainingBytes == 2 ||
862 UNSAFE.getByte(bytes1, baseOffset1 + 2) == UNSAFE.getByte(bytes2, baseOffset2 + 2));
863 }
864 return remainingBytes == 0 ||
865 UNSAFE.getByte(bytes1, baseOffset1) == UNSAFE.getByte(bytes2, baseOffset2);
866 }
867
868 static int equalsConstantTime(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
869 long result = 0;
870 long remainingBytes = length & 7;
871 final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
872 final long end = baseOffset1 + remainingBytes;
873 final long diff = startPos2 - startPos1;
874 for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
875 result |= UNSAFE.getLong(bytes1, i) ^ UNSAFE.getLong(bytes2, i + diff);
876 }
877 if (remainingBytes >= 4) {
878 result |= UNSAFE.getInt(bytes1, baseOffset1) ^ UNSAFE.getInt(bytes2, baseOffset1 + diff);
879 remainingBytes -= 4;
880 }
881 if (remainingBytes >= 2) {
882 long pos = end - remainingBytes;
883 result |= UNSAFE.getChar(bytes1, pos) ^ UNSAFE.getChar(bytes2, pos + diff);
884 remainingBytes -= 2;
885 }
886 if (remainingBytes == 1) {
887 long pos = end - 1;
888 result |= UNSAFE.getByte(bytes1, pos) ^ UNSAFE.getByte(bytes2, pos + diff);
889 }
890 return ConstantTimeUtils.equalsConstantTime(result, 0);
891 }
892
893 static boolean isZero(byte[] bytes, int startPos, int length) {
894 if (length <= 0) {
895 return true;
896 }
897 final long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
898 int remainingBytes = length & 7;
899 final long end = baseOffset + remainingBytes;
900 for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
901 if (UNSAFE.getLong(bytes, i) != 0) {
902 return false;
903 }
904 }
905
906 if (remainingBytes >= 4) {
907 remainingBytes -= 4;
908 if (UNSAFE.getInt(bytes, baseOffset + remainingBytes) != 0) {
909 return false;
910 }
911 }
912 if (remainingBytes >= 2) {
913 return UNSAFE.getChar(bytes, baseOffset) == 0 &&
914 (remainingBytes == 2 || bytes[startPos + 2] == 0);
915 }
916 return bytes[startPos] == 0;
917 }
918
919 static int hashCodeAscii(byte[] bytes, int startPos, int length) {
920 int hash = HASH_CODE_ASCII_SEED;
921 long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
922 final int remainingBytes = length & 7;
923 final long end = baseOffset + remainingBytes;
924 for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
925 hash = hashCodeAsciiCompute(UNSAFE.getLong(bytes, i), hash);
926 }
927 if (remainingBytes == 0) {
928 return hash;
929 }
930 int hcConst = HASH_CODE_C1;
931 if (remainingBytes != 2 & remainingBytes != 4 & remainingBytes != 6) {
932 hash = hash * HASH_CODE_C1 + hashCodeAsciiSanitize(UNSAFE.getByte(bytes, baseOffset));
933 hcConst = HASH_CODE_C2;
934 baseOffset++;
935 }
936 if (remainingBytes != 1 & remainingBytes != 4 & remainingBytes != 5) {
937 hash = hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getShort(bytes, baseOffset));
938 hcConst = hcConst == HASH_CODE_C1 ? HASH_CODE_C2 : HASH_CODE_C1;
939 baseOffset += 2;
940 }
941 if (remainingBytes >= 4) {
942 return hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getInt(bytes, baseOffset));
943 }
944 return hash;
945 }
946
947 static int hashCodeAsciiCompute(long value, int hash) {
948
949
950 return hash * HASH_CODE_C1 +
951
952 hashCodeAsciiSanitize((int) value) * HASH_CODE_C2 +
953
954 (int) ((value & 0x1f1f1f1f00000000L) >>> 32);
955 }
956
957 static int hashCodeAsciiSanitize(int value) {
958 return value & 0x1f1f1f1f;
959 }
960
961 static int hashCodeAsciiSanitize(short value) {
962 return value & 0x1f1f;
963 }
964
965 static int hashCodeAsciiSanitize(byte value) {
966 return value & 0x1f;
967 }
968
969 static ClassLoader getClassLoader(final Class<?> clazz) {
970 if (System.getSecurityManager() == null) {
971 return clazz.getClassLoader();
972 } else {
973 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
974 @Override
975 public ClassLoader run() {
976 return clazz.getClassLoader();
977 }
978 });
979 }
980 }
981
982 static ClassLoader getContextClassLoader() {
983 if (System.getSecurityManager() == null) {
984 return Thread.currentThread().getContextClassLoader();
985 } else {
986 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
987 @Override
988 public ClassLoader run() {
989 return Thread.currentThread().getContextClassLoader();
990 }
991 });
992 }
993 }
994
995 static ClassLoader getSystemClassLoader() {
996 if (System.getSecurityManager() == null) {
997 return ClassLoader.getSystemClassLoader();
998 } else {
999 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
1000 @Override
1001 public ClassLoader run() {
1002 return ClassLoader.getSystemClassLoader();
1003 }
1004 });
1005 }
1006 }
1007
1008 static int addressSize() {
1009 return UNSAFE.addressSize();
1010 }
1011
1012 static long allocateMemory(long size) {
1013 return UNSAFE.allocateMemory(size);
1014 }
1015
1016 static void freeMemory(long address) {
1017 UNSAFE.freeMemory(address);
1018 }
1019
1020 static long reallocateMemory(long address, long newSize) {
1021 return UNSAFE.reallocateMemory(address, newSize);
1022 }
1023
1024 static boolean isAndroid() {
1025 return IS_ANDROID;
1026 }
1027
1028 private static boolean isAndroid0() {
1029
1030
1031
1032
1033
1034
1035
1036 String vmName = SystemPropertyUtil.get("java.vm.name");
1037 boolean isAndroid = "Dalvik".equals(vmName);
1038 if (isAndroid) {
1039 logger.debug("Platform: Android");
1040 }
1041 return isAndroid;
1042 }
1043
1044 private static boolean explicitTryReflectionSetAccessible0() {
1045
1046 return SystemPropertyUtil.getBoolean("io.netty.tryReflectionSetAccessible",
1047 javaVersion() < 9 || RUNNING_IN_NATIVE_IMAGE);
1048 }
1049
1050 static boolean isExplicitTryReflectionSetAccessible() {
1051 return IS_EXPLICIT_TRY_REFLECTION_SET_ACCESSIBLE;
1052 }
1053
1054 static int javaVersion() {
1055 return JAVA_VERSION;
1056 }
1057
1058 private static int javaVersion0() {
1059 final int majorVersion;
1060
1061 if (isAndroid()) {
1062 majorVersion = 6;
1063 } else {
1064 majorVersion = majorVersionFromJavaSpecificationVersion();
1065 }
1066
1067 logger.debug("Java version: {}", majorVersion);
1068
1069 return majorVersion;
1070 }
1071
1072
1073 static int majorVersionFromJavaSpecificationVersion() {
1074 return majorVersion(SystemPropertyUtil.get("java.specification.version", "1.6"));
1075 }
1076
1077
1078 static int majorVersion(final String javaSpecVersion) {
1079 final String[] components = javaSpecVersion.split("\\.");
1080 final int[] version = new int[components.length];
1081 for (int i = 0; i < components.length; i++) {
1082 version[i] = Integer.parseInt(components[i]);
1083 }
1084
1085 if (version[0] == 1) {
1086 assert version[1] >= 6;
1087 return version[1];
1088 } else {
1089 return version[0];
1090 }
1091 }
1092
1093 private PlatformDependent0() {
1094 }
1095 }