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 @Override
96 public boolean hasExpensiveClean() {
97 return false;
98 }
99
100 private static void freeDirectBufferStatic(ByteBuffer buffer) {
101
102
103 if (System.getSecurityManager() == null) {
104 try {
105 INVOKE_CLEANER.invokeExact(buffer);
106 } catch (Throwable cause) {
107 PlatformDependent0.throwException(cause);
108 }
109 } else {
110 freeDirectBufferPrivileged(buffer);
111 }
112 }
113
114 private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
115 Throwable error = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
116 @Override
117 public Throwable run() {
118 try {
119 INVOKE_CLEANER.invokeExact(buffer);
120 } catch (Throwable e) {
121 return e;
122 }
123 return null;
124 }
125 });
126 if (error != null) {
127 PlatformDependent0.throwException(error);
128 }
129 }
130
131 private static final class CleanableDirectBufferImpl implements CleanableDirectBuffer {
132 private final ByteBuffer buffer;
133
134 private CleanableDirectBufferImpl(ByteBuffer buffer) {
135 this.buffer = buffer;
136 PlatformDependent.incrementMemoryCounter(buffer.capacity());
137 }
138
139 @Override
140 public ByteBuffer buffer() {
141 return buffer;
142 }
143
144 @Override
145 public void clean() {
146 int capacity = buffer.capacity();
147 freeDirectBufferStatic(buffer);
148 PlatformDependent.decrementMemoryCounter(capacity);
149 }
150 }
151 }