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