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