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