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.nio.ByteBuffer;
24 import java.security.AccessController;
25 import java.security.PrivilegedAction;
26 import java.util.Objects;
27
28 import static java.lang.invoke.MethodType.methodType;
29
30
31
32
33
34
35
36 final class CleanerJava6 implements Cleaner {
37 private static final MethodHandle CLEAN_METHOD;
38
39 private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava6.class);
40
41 static {
42 MethodHandle clean;
43 Throwable error = null;
44 final ByteBuffer direct = ByteBuffer.allocateDirect(1);
45 try {
46 Object mayBeCleanerField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
47 @Override
48 public Object run() {
49 try {
50 Class<?> cleanerClass = Class.forName("sun.misc.Cleaner");
51 Class<?> directBufClass = Class.forName("sun.nio.ch.DirectBuffer");
52 MethodHandles.Lookup lookup = MethodHandles.lookup();
53
54
55 MethodHandle clean = lookup.findVirtual(
56 cleanerClass, "clean", methodType(void.class));
57
58 MethodHandle nullTest = lookup.findStatic(
59 Objects.class, "nonNull", methodType(boolean.class, Object.class));
60 clean = MethodHandles.guardWithTest(
61 nullTest.asType(methodType(boolean.class, cleanerClass)),
62 clean,
63 nullTest.asType(methodType(void.class, cleanerClass)));
64
65 clean = MethodHandles.filterArguments(clean, 0, lookup.findVirtual(
66 directBufClass,
67 "cleaner",
68 methodType(cleanerClass)));
69
70 clean = MethodHandles.explicitCastArguments(clean,
71 methodType(void.class, ByteBuffer.class));
72 return clean;
73 } catch (Throwable cause) {
74 return cause;
75 }
76 }
77 });
78 if (mayBeCleanerField instanceof Throwable) {
79 throw (Throwable) mayBeCleanerField;
80 }
81
82 clean = (MethodHandle) mayBeCleanerField;
83 clean.invokeExact(direct);
84 } catch (Throwable t) {
85
86 clean = null;
87 error = t;
88 }
89
90 if (error == null) {
91 logger.debug("java.nio.ByteBuffer.cleaner(): available");
92 } else {
93 logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
94 }
95 CLEAN_METHOD = clean;
96 }
97
98 static boolean isSupported() {
99 return CLEAN_METHOD != null;
100 }
101
102 @Override
103 public CleanableDirectBuffer allocate(int capacity) {
104 return new CleanableDirectBufferImpl(ByteBuffer.allocateDirect(capacity));
105 }
106
107 @Deprecated
108 @Override
109 public void freeDirectBuffer(ByteBuffer buffer) {
110 freeDirectBufferStatic(buffer);
111 }
112
113 @Override
114 public boolean hasExpensiveClean() {
115 return false;
116 }
117
118 private static void freeDirectBufferStatic(ByteBuffer buffer) {
119 if (!buffer.isDirect()) {
120 return;
121 }
122 if (System.getSecurityManager() == null) {
123 try {
124 freeDirectBuffer0(buffer);
125 } catch (Throwable cause) {
126 PlatformDependent0.throwException(cause);
127 }
128 } else {
129 freeDirectBufferPrivileged(buffer);
130 }
131 }
132
133 private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
134 Throwable cause = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
135 @Override
136 public Throwable run() {
137 try {
138 freeDirectBuffer0(buffer);
139 return null;
140 } catch (Throwable cause) {
141 return cause;
142 }
143 }
144 });
145 if (cause != null) {
146 PlatformDependent0.throwException(cause);
147 }
148 }
149
150 private static void freeDirectBuffer0(ByteBuffer buffer) throws Throwable {
151 CLEAN_METHOD.invokeExact(buffer);
152 }
153
154 private static final class CleanableDirectBufferImpl implements CleanableDirectBuffer {
155 private final ByteBuffer buffer;
156
157 private CleanableDirectBufferImpl(ByteBuffer buffer) {
158 this.buffer = buffer;
159 PlatformDependent.incrementMemoryCounter(buffer.capacity());
160 }
161
162 @Override
163 public ByteBuffer buffer() {
164 return buffer;
165 }
166
167 @Override
168 public void clean() {
169 int capacity = buffer.capacity();
170 freeDirectBufferStatic(buffer);
171 PlatformDependent.decrementMemoryCounter(capacity);
172 }
173 }
174 }