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