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