1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package org.waarp.compress.zstdunsafe;
35
36 import org.waarp.compress.IncompatibleJvmException;
37 import sun.misc.Unsafe;
38
39 import java.lang.reflect.Field;
40 import java.nio.Buffer;
41 import java.nio.ByteOrder;
42
43 import static java.lang.String.*;
44
45 public final class UnsafeUtil {
46 private static boolean initialized;
47 public static final Unsafe UNSAFE;
48 private static final long ADDRESS_OFFSET;
49
50 private UnsafeUtil() {
51 }
52
53 static {
54 Unsafe tempUnsafe = null;
55 long tempField = 0;
56 try {
57 initLittleEndian();
58 tempUnsafe = initUnsafe();
59 tempField = initAccessor();
60 initialized = true;
61 } catch (final Exception e) {
62 initialized = false;
63 }
64 UNSAFE = tempUnsafe;
65 ADDRESS_OFFSET = tempField;
66 }
67
68 public static boolean isValid() {
69 return initialized;
70 }
71
72
73
74
75 private static final void initLittleEndian() {
76 if (initialized) {
77 return;
78 }
79 final ByteOrder order = ByteOrder.nativeOrder();
80 if (!order.equals(ByteOrder.LITTLE_ENDIAN)) {
81 throw new IncompatibleJvmException(
82 format("Zstandard requires a little endian platform (found %s)",
83 order));
84 }
85 }
86
87
88
89
90 private static final Unsafe initUnsafe() {
91 if (initialized) {
92 return UNSAFE;
93 }
94 try {
95 final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
96 theUnsafe.setAccessible(true);
97 return (Unsafe) theUnsafe.get(null);
98 } catch (final Exception e) {
99 throw new IncompatibleJvmException(
100 "Zstandard requires access to sun.misc.Unsafe");
101 }
102 }
103
104
105
106
107 private static final long initAccessor() {
108 if (initialized) {
109 return ADDRESS_OFFSET;
110 }
111 try {
112
113 final Class cls =
114 Class.forName("jdk.internal.module.IllegalAccessLogger");
115 final Field logger = cls.getDeclaredField("logger");
116 UNSAFE.putObjectVolatile(cls, UNSAFE.staticFieldOffset(logger), null);
117
118
119 return UNSAFE.objectFieldOffset(Buffer.class.getDeclaredField("address"));
120 } catch (final Exception e) {
121 throw new IncompatibleJvmException(
122 "Zstandard requires access to java.nio.Buffer raw address field");
123 }
124 }
125
126 public static final long getAddress(final Buffer buffer) {
127 if (!buffer.isDirect()) {
128 throw new IllegalArgumentException("buffer is not direct");
129 }
130 return UNSAFE.getLong(buffer, ADDRESS_OFFSET);
131 }
132 }