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
37 final class CleanerJava6 implements Cleaner {
38 private static final MethodHandle CLEAN_METHOD;
39
40 private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava6.class);
41
42 static {
43 MethodHandle clean;
44 Throwable error = null;
45 final ByteBuffer direct = ByteBuffer.allocateDirect(1);
46 try {
47 Object mayBeCleanerField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
48 @Override
49 public Object run() {
50 try {
51 Class<?> cleanerClass = Class.forName("sun.misc.Cleaner");
52 Class<?> directBufClass = Class.forName("sun.nio.ch.DirectBuffer");
53 MethodHandles.Lookup lookup = MethodHandles.lookup();
54
55
56 MethodHandle clean = lookup.findVirtual(
57 cleanerClass, "clean", methodType(void.class));
58
59 MethodHandle nullTest = lookup.findStatic(
60 Objects.class, "nonNull", methodType(boolean.class, Object.class));
61 clean = MethodHandles.guardWithTest(
62 nullTest.asType(methodType(boolean.class, cleanerClass)),
63 clean,
64 nullTest.asType(methodType(void.class, cleanerClass)));
65
66 clean = MethodHandles.filterArguments(clean, 0, lookup.findVirtual(
67 directBufClass,
68 "cleaner",
69 methodType(cleanerClass)));
70
71 clean = MethodHandles.explicitCastArguments(clean,
72 methodType(void.class, ByteBuffer.class));
73 return clean;
74 } catch (Throwable cause) {
75 return cause;
76 }
77 }
78 });
79 if (mayBeCleanerField instanceof Throwable) {
80 throw (Throwable) mayBeCleanerField;
81 }
82
83 clean = (MethodHandle) mayBeCleanerField;
84 clean.invokeExact(direct);
85 } catch (Throwable t) {
86
87 clean = null;
88 error = t;
89 }
90
91 if (error == null) {
92 logger.debug("java.nio.ByteBuffer.cleaner(): available");
93 } else {
94 logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
95 }
96 CLEAN_METHOD = clean;
97 }
98
99 static boolean isSupported() {
100 return CLEAN_METHOD != null;
101 }
102
103 @Override
104 public void freeDirectBuffer(ByteBuffer buffer) {
105 if (!buffer.isDirect()) {
106 return;
107 }
108 if (System.getSecurityManager() == null) {
109 try {
110 freeDirectBuffer0(buffer);
111 } catch (Throwable cause) {
112 PlatformDependent0.throwException(cause);
113 }
114 } else {
115 freeDirectBufferPrivileged(buffer);
116 }
117 }
118
119 private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
120 Throwable cause = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
121 @Override
122 public Throwable run() {
123 try {
124 freeDirectBuffer0(buffer);
125 return null;
126 } catch (Throwable cause) {
127 return cause;
128 }
129 }
130 });
131 if (cause != null) {
132 PlatformDependent0.throwException(cause);
133 }
134 }
135
136 private static void freeDirectBuffer0(ByteBuffer buffer) throws Throwable {
137 CLEAN_METHOD.invokeExact(buffer);
138 }
139 }