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 void freeDirectBuffer(ByteBuffer buffer) {
86
87
88 if (System.getSecurityManager() == null) {
89 try {
90 INVOKE_CLEANER.invokeExact(buffer);
91 } catch (Throwable cause) {
92 PlatformDependent0.throwException(cause);
93 }
94 } else {
95 freeDirectBufferPrivileged(buffer);
96 }
97 }
98
99 private static void freeDirectBufferPrivileged(final ByteBuffer buffer) {
100 Throwable error = AccessController.doPrivileged(new PrivilegedAction<Throwable>() {
101 @Override
102 public Throwable run() {
103 try {
104 INVOKE_CLEANER.invokeExact(buffer);
105 } catch (Throwable e) {
106 return e;
107 }
108 return null;
109 }
110 });
111 if (error != null) {
112 PlatformDependent0.throwException(error);
113 }
114 }
115 }