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 }