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