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 private static void freeDirectBufferStatic(ByteBuffer buffer) {
114 if (!buffer.isDirect()) {
115 return;
116 }
117 if (System.getSecurityManager() == null) {
118 try {
119 freeDirectBuffer0(buffer);
120 } catch (Throwable cause) {
121 PlatformDependent0.throwException(cause);
122 }
123 } else {
124 freeDirectBufferPrivileged(buffer);
125 }
126 }
127
128 private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
129 Throwable cause = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
130 @Override
131 public Throwable run() {
132 try {
133 freeDirectBuffer0(buffer);
134 return null;
135 } catch (Throwable cause) {
136 return cause;
137 }
138 }
139 });
140 if (cause != null) {
141 PlatformDependent0.throwException(cause);
142 }
143 }
144
145 private static void freeDirectBuffer0(ByteBuffer buffer) throws Throwable {
146 CLEAN_METHOD.invokeExact(buffer);
147 }
148
149 private static final class CleanableDirectBufferImpl implements CleanableDirectBuffer {
150 private final ByteBuffer buffer;
151
152 private CleanableDirectBufferImpl(ByteBuffer buffer) {
153 this.buffer = buffer;
154 }
155
156 @Override
157 public ByteBuffer buffer() {
158 return buffer;
159 }
160
161 @Override
162 public void clean() {
163 freeDirectBufferStatic(buffer);
164 }
165 }
166 }