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
27 import static java.lang.invoke.MethodType.methodType;
28
29
30
31
32 final class CleanerJava9 implements Cleaner {
33 private static final InternalLogger logger = InternalLoggerFactory.getInstance(CleanerJava9.class);
34
35 private static final MethodHandle INVOKE_CLEANER;
36
37 static {
38 final MethodHandle method;
39 final Throwable error;
40 if (SunMiscUnsafeAccess.isAvailabile()) {
41 final ByteBuffer buffer = ByteBuffer.allocateDirect(1);
42 Object maybeInvokeMethod = AccessController.doPrivileged(new PrivilegedAction<Object>() {
43 @Override
44 public Object run() {
45 try {
46
47 Class<?> unsafeClass = SunMiscUnsafeAccess.UNSAFE.getClass();
48 MethodHandles.Lookup lookup = MethodHandles.lookup();
49 MethodHandle invokeCleaner = lookup.findVirtual(
50 unsafeClass, "invokeCleaner", methodType(void.class, ByteBuffer.class));
51 invokeCleaner = invokeCleaner.bindTo(SunMiscUnsafeAccess.UNSAFE);
52 invokeCleaner.invokeExact(buffer);
53 return invokeCleaner;
54 } catch (Throwable e) {
55 return e;
56 }
57 }
58 });
59
60 if (maybeInvokeMethod instanceof Throwable) {
61 method = null;
62 error = (Throwable) maybeInvokeMethod;
63 } else {
64 method = (MethodHandle) maybeInvokeMethod;
65 error = null;
66 }
67 } else {
68 method = null;
69 error = new UnsupportedOperationException("sun.misc.Unsafe unavailable",
70 SunMiscUnsafeAccess.unavailabilityCause());
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 }