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