28package com.jogamp.common.util;
30import java.lang.reflect.Field;
31import java.lang.reflect.InvocationTargetException;
32import java.lang.reflect.Method;
33import java.nio.ByteBuffer;
34import java.security.PrivilegedAction;
36import com.jogamp.common.ExceptionUtils;
38import jogamp.common.Debug;
39import jogamp.common.os.PlatformPropsImpl;
46 static final boolean DEBUG;
48 DEBUG = Debug.debug(
"UnsafeUtil");
53 private static final Object theUnsafe;
54 private static final Method unsafeCleanBB;
55 private static volatile boolean hasUnsafeCleanBBError;
57 private static final Method staticFieldOffset;
58 private static final Method getObjectVolatile;
59 private static final Method putObjectVolatile;
60 private static volatile boolean hasGetPutObjectVolatile;
62 private static final Class<?> illegalAccessLoggerClass;
63 private static final Long illegalAccessLoggerOffset;
64 private static final Object illegalAccessLoggerSync =
new Object();
65 private static volatile boolean hasIllegalAccessError;
68 final Object[] _theUnsafe = {
null };
69 final Method[] _cleanBB = {
null };
70 final Method[] _staticFieldOffset = {
null };
71 final Method[] _objectVolatile = {
null,
null };
72 final Class<?>[] _illegalAccessLoggerClass = {
null };
73 final Long[] _loggerOffset = {
null };
75 SecurityUtil.doPrivileged(
new PrivilegedAction<Object>() {
78 Class<?> unsafeClass =
null;
81 unsafeClass = Class.forName(
"sun.misc.Unsafe");
83 final Field f = unsafeClass.getDeclaredField(
"theUnsafe");
84 f.setAccessible(
true);
85 _theUnsafe[0] = f.get(
null);
87 _cleanBB[0] = unsafeClass.getMethod(
"invokeCleaner", java.nio.ByteBuffer.class);
88 _cleanBB[0].setAccessible(
true);
89 }
catch(
final Throwable t) {
91 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
94 if(
null != _theUnsafe[0] && PlatformPropsImpl.JAVA_9 ) {
96 _staticFieldOffset[0] = unsafeClass.getDeclaredMethod(
"staticFieldOffset", Field.class);
97 _objectVolatile[0] = unsafeClass.getDeclaredMethod(
"getObjectVolatile", Object.class,
long.class);
98 _objectVolatile[1] = unsafeClass.getDeclaredMethod(
"putObjectVolatile", Object.class,
long.class, Object.class);
100 if( PlatformPropsImpl.JAVA_9 ) {
101 _illegalAccessLoggerClass[0] = Class.forName(
"jdk.internal.module.IllegalAccessLogger");
102 final Field loggerField = _illegalAccessLoggerClass[0].getDeclaredField(
"logger");
103 _loggerOffset[0] = (Long) _staticFieldOffset[0].invoke(_theUnsafe[0], loggerField);
105 }
catch(
final Throwable t) {
107 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
113 theUnsafe = _theUnsafe[0];
114 unsafeCleanBB = _cleanBB[0];
115 hasUnsafeCleanBBError =
null == theUnsafe ||
null == unsafeCleanBB;
117 System.err.println(
"UnsafeUtil.init: hasTheUnsafe: "+(
null!=theUnsafe)+
", hasInvokeCleaner: "+!hasUnsafeCleanBBError);
120 staticFieldOffset = _staticFieldOffset[0];
121 getObjectVolatile = _objectVolatile[0];
122 putObjectVolatile = _objectVolatile[1];
123 hasGetPutObjectVolatile =
null != staticFieldOffset &&
null != getObjectVolatile &&
null != putObjectVolatile;
124 illegalAccessLoggerClass = _illegalAccessLoggerClass[0];
125 illegalAccessLoggerOffset = _loggerOffset[0];
126 hasIllegalAccessError = !hasGetPutObjectVolatile ||
null == illegalAccessLoggerClass ||
null == illegalAccessLoggerOffset;
128 System.err.println(
"UnsafeUtil.init: hasUnsafeGetPutObjectVolatile: "+hasGetPutObjectVolatile+
", hasUnsafeIllegalAccessLogger: "+!hasIllegalAccessError);
149 if( hasUnsafeCleanBBError || !bb.isDirect() ) {
153 unsafeCleanBB.invoke(theUnsafe, bb);
155 }
catch(
final Throwable t) {
156 hasUnsafeCleanBBError =
true;
185 if( !hasIllegalAccessError ) {
186 synchronized(illegalAccessLoggerSync) {
187 final Object newLogger =
null;
188 Object oldLogger =
null;
190 oldLogger = getObjectVolatile.invoke(theUnsafe, illegalAccessLoggerClass, illegalAccessLoggerOffset);
191 putObjectVolatile.invoke(theUnsafe, illegalAccessLoggerClass, illegalAccessLoggerOffset, newLogger);
192 }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
194 hasIllegalAccessError =
true;
202 }
catch (
final Throwable t) {
206 throw new RuntimeException(t);
209 putObjectVolatile.invoke(theUnsafe, illegalAccessLoggerClass, illegalAccessLoggerOffset, oldLogger);
210 }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
212 hasIllegalAccessError =
true;
213 throw new InternalError(e);
static void dumpThrowable(final String additionalDescr, final Throwable t)
Dumps a Throwable to System.err in a decorating message including the current thread name,...
Utility methods allowing easy access to certain sun.misc.Unsafe functionality.
static boolean hasIllegalAccessLoggerAccess()
Returns true if access to jdk.internal.module.IllegalAcessLogger's logger field is available and has ...
static boolean invokeCleaner(final ByteBuffer bb)
Access to sun.misc.Unsafe.invokeCleaner(java.nio.ByteBuffer).
static< T > T doWithoutIllegalAccessLogger(final PrivilegedAction< T > action)
Issue the given user action while jdk.internal.module.IllegalAcessLogger's logger has been temporaril...
static boolean hasInvokeCleaner()
Returns true if sun.misc.Unsafe.invokeCleaner(java.nio.ByteBuffer) is available and has not caused an...