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
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 void safeConstructPutInt(Object object, long fieldOffset, int value) {
683 UNSAFE.putInt(object, fieldOffset, value);
684 UNSAFE.storeFence();
685 }
686
687 private static long getLong(Object object, long fieldOffset) {
688 return UNSAFE.getLong(object, fieldOffset);
689 }
690
691 static long objectFieldOffset(Field field) {
692 return UNSAFE.objectFieldOffset(field);
693 }
694
695 static byte getByte(long address) {
696 return UNSAFE.getByte(address);
697 }
698
699 static short getShort(long address) {
700 return UNSAFE.getShort(address);
701 }
702
703 static int getInt(long address) {
704 return UNSAFE.getInt(address);
705 }
706
707 static long getLong(long address) {
708 return UNSAFE.getLong(address);
709 }
710
711 static byte getByte(byte[] data, int index) {
712 return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
713 }
714
715 static byte getByte(byte[] data, long index) {
716 return UNSAFE.getByte(data, BYTE_ARRAY_BASE_OFFSET + index);
717 }
718
719 static short getShort(byte[] data, int index) {
720 return UNSAFE.getShort(data, BYTE_ARRAY_BASE_OFFSET + index);
721 }
722
723 static int getInt(byte[] data, int index) {
724 return UNSAFE.getInt(data, BYTE_ARRAY_BASE_OFFSET + index);
725 }
726
727 static int getInt(int[] data, long index) {
728 return UNSAFE.getInt(data, INT_ARRAY_BASE_OFFSET + INT_ARRAY_INDEX_SCALE * index);
729 }
730
731 static int getIntVolatile(long address) {
732 return UNSAFE.getIntVolatile(null, address);
733 }
734
735 static void putIntOrdered(long address, int newValue) {
736 UNSAFE.putOrderedInt(null, address, newValue);
737 }
738
739 static long getLong(byte[] data, int index) {
740 return UNSAFE.getLong(data, BYTE_ARRAY_BASE_OFFSET + index);
741 }
742
743 static long getLong(long[] data, long index) {
744 return UNSAFE.getLong(data, LONG_ARRAY_BASE_OFFSET + LONG_ARRAY_INDEX_SCALE * index);
745 }
746
747 static void putByte(long address, byte value) {
748 UNSAFE.putByte(address, value);
749 }
750
751 static void putShort(long address, short value) {
752 UNSAFE.putShort(address, value);
753 }
754
755 static void putShortOrdered(long address, short newValue) {
756 UNSAFE.storeFence();
757 UNSAFE.putShort(null, address, newValue);
758 }
759
760 static void putInt(long address, int value) {
761 UNSAFE.putInt(address, value);
762 }
763
764 static void putLong(long address, long value) {
765 UNSAFE.putLong(address, value);
766 }
767
768 static void putByte(byte[] data, int index, byte value) {
769 UNSAFE.putByte(data, BYTE_ARRAY_BASE_OFFSET + index, value);
770 }
771
772 static void putByte(Object data, long offset, byte value) {
773 UNSAFE.putByte(data, offset, value);
774 }
775
776 static void putShort(byte[] data, int index, short value) {
777 UNSAFE.putShort(data, BYTE_ARRAY_BASE_OFFSET + index, value);
778 }
779
780 static void putInt(byte[] data, int index, int value) {
781 UNSAFE.putInt(data, BYTE_ARRAY_BASE_OFFSET + index, value);
782 }
783
784 static void putLong(byte[] data, int index, long value) {
785 UNSAFE.putLong(data, BYTE_ARRAY_BASE_OFFSET + index, value);
786 }
787
788 static void putObject(Object o, long offset, Object x) {
789 UNSAFE.putObject(o, offset, x);
790 }
791
792 static void copyMemory(long srcAddr, long dstAddr, long length) {
793
794
795 if (javaVersion() <= 8) {
796 copyMemoryWithSafePointPolling(srcAddr, dstAddr, length);
797 } else {
798 UNSAFE.copyMemory(srcAddr, dstAddr, length);
799 }
800 }
801
802 private static void copyMemoryWithSafePointPolling(long srcAddr, long dstAddr, long length) {
803 while (length > 0) {
804 long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
805 UNSAFE.copyMemory(srcAddr, dstAddr, size);
806 length -= size;
807 srcAddr += size;
808 dstAddr += size;
809 }
810 }
811
812 static void copyMemory(Object src, long srcOffset, Object dst, long dstOffset, long length) {
813
814
815 if (javaVersion() <= 8) {
816 copyMemoryWithSafePointPolling(src, srcOffset, dst, dstOffset, length);
817 } else {
818 UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, length);
819 }
820 }
821
822 private static void copyMemoryWithSafePointPolling(
823 Object src, long srcOffset, Object dst, long dstOffset, long length) {
824 while (length > 0) {
825 long size = Math.min(length, UNSAFE_COPY_THRESHOLD);
826 UNSAFE.copyMemory(src, srcOffset, dst, dstOffset, size);
827 length -= size;
828 srcOffset += size;
829 dstOffset += size;
830 }
831 }
832
833 static void setMemory(long address, long bytes, byte value) {
834 UNSAFE.setMemory(address, bytes, value);
835 }
836
837 static void setMemory(Object o, long offset, long bytes, byte value) {
838 UNSAFE.setMemory(o, offset, bytes, value);
839 }
840
841 static boolean equals(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
842 int remainingBytes = length & 7;
843 final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
844 final long diff = startPos2 - startPos1;
845 if (length >= 8) {
846 final long end = baseOffset1 + remainingBytes;
847 for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
848 if (UNSAFE.getLong(bytes1, i) != UNSAFE.getLong(bytes2, i + diff)) {
849 return false;
850 }
851 }
852 }
853 if (remainingBytes >= 4) {
854 remainingBytes -= 4;
855 long pos = baseOffset1 + remainingBytes;
856 if (UNSAFE.getInt(bytes1, pos) != UNSAFE.getInt(bytes2, pos + diff)) {
857 return false;
858 }
859 }
860 final long baseOffset2 = baseOffset1 + diff;
861 if (remainingBytes >= 2) {
862 return UNSAFE.getChar(bytes1, baseOffset1) == UNSAFE.getChar(bytes2, baseOffset2) &&
863 (remainingBytes == 2 ||
864 UNSAFE.getByte(bytes1, baseOffset1 + 2) == UNSAFE.getByte(bytes2, baseOffset2 + 2));
865 }
866 return remainingBytes == 0 ||
867 UNSAFE.getByte(bytes1, baseOffset1) == UNSAFE.getByte(bytes2, baseOffset2);
868 }
869
870 static int equalsConstantTime(byte[] bytes1, int startPos1, byte[] bytes2, int startPos2, int length) {
871 long result = 0;
872 long remainingBytes = length & 7;
873 final long baseOffset1 = BYTE_ARRAY_BASE_OFFSET + startPos1;
874 final long end = baseOffset1 + remainingBytes;
875 final long diff = startPos2 - startPos1;
876 for (long i = baseOffset1 - 8 + length; i >= end; i -= 8) {
877 result |= UNSAFE.getLong(bytes1, i) ^ UNSAFE.getLong(bytes2, i + diff);
878 }
879 if (remainingBytes >= 4) {
880 result |= UNSAFE.getInt(bytes1, baseOffset1) ^ UNSAFE.getInt(bytes2, baseOffset1 + diff);
881 remainingBytes -= 4;
882 }
883 if (remainingBytes >= 2) {
884 long pos = end - remainingBytes;
885 result |= UNSAFE.getChar(bytes1, pos) ^ UNSAFE.getChar(bytes2, pos + diff);
886 remainingBytes -= 2;
887 }
888 if (remainingBytes == 1) {
889 long pos = end - 1;
890 result |= UNSAFE.getByte(bytes1, pos) ^ UNSAFE.getByte(bytes2, pos + diff);
891 }
892 return ConstantTimeUtils.equalsConstantTime(result, 0);
893 }
894
895 static boolean isZero(byte[] bytes, int startPos, int length) {
896 if (length <= 0) {
897 return true;
898 }
899 final long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
900 int remainingBytes = length & 7;
901 final long end = baseOffset + remainingBytes;
902 for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
903 if (UNSAFE.getLong(bytes, i) != 0) {
904 return false;
905 }
906 }
907
908 if (remainingBytes >= 4) {
909 remainingBytes -= 4;
910 if (UNSAFE.getInt(bytes, baseOffset + remainingBytes) != 0) {
911 return false;
912 }
913 }
914 if (remainingBytes >= 2) {
915 return UNSAFE.getChar(bytes, baseOffset) == 0 &&
916 (remainingBytes == 2 || bytes[startPos + 2] == 0);
917 }
918 return bytes[startPos] == 0;
919 }
920
921 static int hashCodeAscii(byte[] bytes, int startPos, int length) {
922 int hash = HASH_CODE_ASCII_SEED;
923 long baseOffset = BYTE_ARRAY_BASE_OFFSET + startPos;
924 final int remainingBytes = length & 7;
925 final long end = baseOffset + remainingBytes;
926 for (long i = baseOffset - 8 + length; i >= end; i -= 8) {
927 hash = hashCodeAsciiCompute(UNSAFE.getLong(bytes, i), hash);
928 }
929 if (remainingBytes == 0) {
930 return hash;
931 }
932 int hcConst = HASH_CODE_C1;
933 if (remainingBytes != 2 & remainingBytes != 4 & remainingBytes != 6) {
934 hash = hash * HASH_CODE_C1 + hashCodeAsciiSanitize(UNSAFE.getByte(bytes, baseOffset));
935 hcConst = HASH_CODE_C2;
936 baseOffset++;
937 }
938 if (remainingBytes != 1 & remainingBytes != 4 & remainingBytes != 5) {
939 hash = hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getShort(bytes, baseOffset));
940 hcConst = hcConst == HASH_CODE_C1 ? HASH_CODE_C2 : HASH_CODE_C1;
941 baseOffset += 2;
942 }
943 if (remainingBytes >= 4) {
944 return hash * hcConst + hashCodeAsciiSanitize(UNSAFE.getInt(bytes, baseOffset));
945 }
946 return hash;
947 }
948
949 static int hashCodeAsciiCompute(long value, int hash) {
950
951
952 return hash * HASH_CODE_C1 +
953
954 hashCodeAsciiSanitize((int) value) * HASH_CODE_C2 +
955
956 (int) ((value & 0x1f1f1f1f00000000L) >>> 32);
957 }
958
959 static int hashCodeAsciiSanitize(int value) {
960 return value & 0x1f1f1f1f;
961 }
962
963 static int hashCodeAsciiSanitize(short value) {
964 return value & 0x1f1f;
965 }
966
967 static int hashCodeAsciiSanitize(byte value) {
968 return value & 0x1f;
969 }
970
971 static ClassLoader getClassLoader(final Class<?> clazz) {
972 if (System.getSecurityManager() == null) {
973 return clazz.getClassLoader();
974 } else {
975 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
976 @Override
977 public ClassLoader run() {
978 return clazz.getClassLoader();
979 }
980 });
981 }
982 }
983
984 static ClassLoader getContextClassLoader() {
985 if (System.getSecurityManager() == null) {
986 return Thread.currentThread().getContextClassLoader();
987 } else {
988 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
989 @Override
990 public ClassLoader run() {
991 return Thread.currentThread().getContextClassLoader();
992 }
993 });
994 }
995 }
996
997 static ClassLoader getSystemClassLoader() {
998 if (System.getSecurityManager() == null) {
999 return ClassLoader.getSystemClassLoader();
1000 } else {
1001 return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
1002 @Override
1003 public ClassLoader run() {
1004 return ClassLoader.getSystemClassLoader();
1005 }
1006 });
1007 }
1008 }
1009
1010 static int addressSize() {
1011 return UNSAFE.addressSize();
1012 }
1013
1014 static long allocateMemory(long size) {
1015 return UNSAFE.allocateMemory(size);
1016 }
1017
1018 static void freeMemory(long address) {
1019 UNSAFE.freeMemory(address);
1020 }
1021
1022 static long reallocateMemory(long address, long newSize) {
1023 return UNSAFE.reallocateMemory(address, newSize);
1024 }
1025
1026 static boolean isAndroid() {
1027 return IS_ANDROID;
1028 }
1029
1030 private static boolean isAndroid0() {
1031
1032
1033
1034
1035
1036
1037
1038 String vmName = SystemPropertyUtil.get("java.vm.name");
1039 boolean isAndroid = "Dalvik".equals(vmName);
1040 if (isAndroid) {
1041 logger.debug("Platform: Android");
1042 }
1043 return isAndroid;
1044 }
1045
1046 private static boolean explicitTryReflectionSetAccessible0() {
1047
1048 return SystemPropertyUtil.getBoolean("io.netty.tryReflectionSetAccessible",
1049 javaVersion() < 9 || RUNNING_IN_NATIVE_IMAGE);
1050 }
1051
1052 static boolean isExplicitTryReflectionSetAccessible() {
1053 return IS_EXPLICIT_TRY_REFLECTION_SET_ACCESSIBLE;
1054 }
1055
1056 static int javaVersion() {
1057 return JAVA_VERSION;
1058 }
1059
1060 private static int javaVersion0() {
1061 final int majorVersion;
1062
1063 if (isAndroid()) {
1064 majorVersion = 6;
1065 } else {
1066 majorVersion = majorVersionFromJavaSpecificationVersion();
1067 }
1068
1069 logger.debug("Java version: {}", majorVersion);
1070
1071 return majorVersion;
1072 }
1073
1074
1075 static int majorVersionFromJavaSpecificationVersion() {
1076 return majorVersion(SystemPropertyUtil.get("java.specification.version", "1.6"));
1077 }
1078
1079
1080 static int majorVersion(final String javaSpecVersion) {
1081 final String[] components = javaSpecVersion.split("\\.");
1082 final int[] version = new int[components.length];
1083 for (int i = 0; i < components.length; i++) {
1084 version[i] = Integer.parseInt(components[i]);
1085 }
1086
1087 if (version[0] == 1) {
1088 assert version[1] >= 6;
1089 return version[1];
1090 } else {
1091 return version[0];
1092 }
1093 }
1094
1095 private PlatformDependent0() {
1096 }
1097 }