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