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 import sun.misc.Unsafe;
21
22 import java.lang.invoke.MethodHandle;
23 import java.lang.invoke.MethodHandles;
24 import java.nio.ByteBuffer;
25 import java.security.AccessController;
26 import java.security.PrivilegedAction;
27
28 import static java.lang.invoke.MethodType.methodType;
29
30
31
32
33 final class CleanerJava9 implements Cleaner {
34 private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava9.class);
35
36 private static final MethodHandle INVOKE_CLEANER;
37
38 static {
39 final MethodHandle method;
40 final Throwable error;
41 if (PlatformDependent0.hasUnsafe()) {
42 final ByteBuffer buffer = ByteBuffer.allocateDirect(1);
43 Object maybeInvokeMethod = AccessController.doPrivileged(new PrivilegedAction<Object>() {
44 @Override
45 public Object run() {
46 try {
47
48 Class<? extends Unsafe> unsafeClass = PlatformDependent0.UNSAFE.getClass();
49 MethodHandles.Lookup lookup = MethodHandles.lookup();
50 MethodHandle invokeCleaner = lookup.findVirtual(
51 unsafeClass, "invokeCleaner", methodType(void.class, ByteBuffer.class));
52 invokeCleaner = invokeCleaner.bindTo(PlatformDependent0.UNSAFE);
53 invokeCleaner.invokeExact(buffer);
54 return invokeCleaner;
55 } catch (Throwable e) {
56 return e;
57 }
58 }
59 });
60
61 if (maybeInvokeMethod instanceof Throwable) {
62 method = null;
63 error = (Throwable) maybeInvokeMethod;
64 } else {
65 method = (MethodHandle) maybeInvokeMethod;
66 error = null;
67 }
68 } else {
69 method = null;
70 error = new UnsupportedOperationException("sun.misc.Unsafe unavailable");
71 }
72 if (error == null) {
73 logger.debug("java.nio.ByteBuffer.cleaner(): available");
74 } else {
75 logger.debug("java.nio.ByteBuffer.cleaner(): unavailable", error);
76 }
77 INVOKE_CLEANER = method;
78 }
79
80 static boolean isSupported() {
81 return INVOKE_CLEANER != null;
82 }
83
84 @Override
85 public CleanableDirectBuffer allocate(int capacity) {
86 return new CleanableDirectBufferImpl(ByteBuffer.allocateDirect(capacity));
87 }
88
89 @Deprecated
90 @Override
91 public void freeDirectBuffer(ByteBuffer buffer) {
92 freeDirectBufferStatic(buffer);
93 }
94
95 private static void freeDirectBufferStatic(ByteBuffer buffer) {
96
97
98 if (System.getSecurityManager() == null) {
99 try {
100 INVOKE_CLEANER.invokeExact(buffer);
101 } catch (Throwable cause) {
102 PlatformDependent0.throwException(cause);
103 }
104 } else {
105 freeDirectBufferPrivileged(buffer);
106 }
107 }
108
109 private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
110 Throwable error = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
111 @Override
112 public Throwable run() {
113 try {
114 INVOKE_CLEANER.invokeExact(buffer);
115 } catch (Throwable e) {
116 return e;
117 }
118 return null;
119 }
120 });
121 if (error != null) {
122 PlatformDependent0.throwException(error);
123 }
124 }
125
126 private static final class CleanableDirectBufferImpl implements CleanableDirectBuffer {
127 private final ByteBuffer buffer;
128
129 private CleanableDirectBufferImpl(ByteBuffer buffer) {
130 this.buffer = buffer;
131 }
132
133 @Override
134 public ByteBuffer buffer() {
135 return buffer;
136 }
137
138 @Override
139 public void clean() {
140 freeDirectBufferStatic(buffer);
141 }
142 }
143 }