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