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 m_getObject;
58 private static final Method m_putObject;
59 private static final Method m_getObjectVolatile;
60 private static final Method m_putObjectVolatile;
62 private static final Method m_getLong;
63 private static final Method m_putLong;
65 private static final Method m_staticFieldOffset;
67 private static final Class<?> c_illegalAccessLoggerClass;
68 private static final Long o_illegalAccessLoggerOffset;
69 private static final Object o_illegalAccessLoggerSync =
new Object();
70 private static volatile boolean hasIllegalAccessError;
73 final Object[] _theUnsafe = {
null };
74 final Method[] _cleanBB = {
null };
75 final Method[] _staticFieldOffset = {
null };
76 final Method[] _getPutObject = {
null,
null };
77 final Method[] _getPutObjectVolatile = {
null,
null };
78 final Method[] _getPutLong = {
null,
null };
79 final Class<?>[] _illegalAccessLoggerClass = {
null };
80 final Long[] _loggerOffset = {
null };
82 SecurityUtil.doPrivileged(
new PrivilegedAction<Object>() {
85 Class<?> unsafeClass =
null;
88 unsafeClass = Class.forName(
"sun.misc.Unsafe");
90 final Field f = unsafeClass.getDeclaredField(
"theUnsafe");
91 f.setAccessible(
true);
92 _theUnsafe[0] = f.get(
null);
94 _cleanBB[0] = unsafeClass.getMethod(
"invokeCleaner", java.nio.ByteBuffer.class);
95 _cleanBB[0].setAccessible(
true);
96 }
catch(
final Throwable t) {
98 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
101 if(
null != _theUnsafe[0] ) {
103 _getPutObject[0] = unsafeClass.getDeclaredMethod(
"getObject", Object.class,
long.class);
104 _getPutObject[1] = unsafeClass.getDeclaredMethod(
"putObject", Object.class,
long.class, Object.class);
105 }
catch(
final Throwable t) {
107 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
111 _getPutObjectVolatile[0] = unsafeClass.getDeclaredMethod(
"getObjectVolatile", Object.class,
long.class);
112 _getPutObjectVolatile[1] = unsafeClass.getDeclaredMethod(
"putObjectVolatile", Object.class,
long.class, Object.class);
113 }
catch(
final Throwable t) {
115 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
119 _getPutLong[0] = unsafeClass.getDeclaredMethod(
"getLong", Object.class,
long.class);
120 _getPutLong[1] = unsafeClass.getDeclaredMethod(
"putLong", Object.class,
long.class,
long.class);
121 }
catch(
final Throwable t) {
123 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
127 _staticFieldOffset[0] = unsafeClass.getDeclaredMethod(
"staticFieldOffset", Field.class);
128 }
catch(
final Throwable t) {
130 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
133 if( PlatformPropsImpl.JAVA_9 &&
null != _staticFieldOffset[0] ) {
135 _illegalAccessLoggerClass[0] = Class.forName(
"jdk.internal.module.IllegalAccessLogger");
136 final Field loggerField = _illegalAccessLoggerClass[0].getDeclaredField(
"logger");
137 _loggerOffset[0] = (Long) _staticFieldOffset[0].invoke(_theUnsafe[0], loggerField);
138 }
catch(
final Throwable t) {
140 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
147 theUnsafe = _theUnsafe[0];
148 unsafeCleanBB = _cleanBB[0];
149 hasUnsafeCleanBBError =
null == theUnsafe ||
null == unsafeCleanBB;
151 System.err.println(
"UnsafeUtil.init: hasTheUnsafe: "+(
null!=theUnsafe)+
", hasInvokeCleaner: "+!hasUnsafeCleanBBError);
153 m_staticFieldOffset = _staticFieldOffset[0];
154 m_getObject = _getPutObject[0];
155 m_putObject = _getPutObject[1];
156 m_getObjectVolatile = _getPutObjectVolatile[0];
157 m_putObjectVolatile = _getPutObjectVolatile[1];
158 m_getLong = _getPutLong[0];
159 m_putLong = _getPutLong[1];
160 c_illegalAccessLoggerClass = _illegalAccessLoggerClass[0];
161 o_illegalAccessLoggerOffset = _loggerOffset[0];
162 hasIllegalAccessError =
null == m_getObjectVolatile ||
null == m_putObjectVolatile ||
163 null == c_illegalAccessLoggerClass ||
null == o_illegalAccessLoggerOffset;
165 System.err.println(
"UnsafeUtil.init: hasUnsafeIllegalAccessLogger: "+!hasIllegalAccessError);
186 if( hasUnsafeCleanBBError || !bb.isDirect() ) {
190 unsafeCleanBB.invoke(theUnsafe, bb);
192 }
catch(
final Throwable t) {
193 hasUnsafeCleanBBError =
true;
202 if(
null != m_staticFieldOffset) {
203 throw new UnsupportedOperationException(
"staticFieldOffset");
206 final Long res = (Long)m_staticFieldOffset.invoke(theUnsafe, f);
208 return res.longValue();
210 throw new RuntimeException(
"staticFieldOffset: f "+f);
211 }
catch (IllegalAccessException | InvocationTargetException e) {
212 throw new RuntimeException(
"UnsafeUtil");
216 public static Object
getObject(
final Object o,
final long offset) {
217 if(
null != m_getObject) {
218 throw new UnsupportedOperationException(
"getObject");
221 return m_getObject.invoke(theUnsafe, o, offset);
222 }
catch (IllegalAccessException | InvocationTargetException e) {
223 throw new RuntimeException(
"UnsafeUtil: o "+o+
", offset "+offset, e);
226 public static void putObject(
final Object o,
final long offset,
final Object x) {
227 if(
null != m_putObject) {
228 throw new UnsupportedOperationException(
"putObject");
231 m_putObject.invoke(theUnsafe, o, offset, x);
232 }
catch (IllegalAccessException | InvocationTargetException e) {
233 throw new RuntimeException(
"UnsafeUtil");
238 if(
null != m_getObjectVolatile) {
239 throw new UnsupportedOperationException(
"getObjectVolatile");
242 return m_getObjectVolatile.invoke(theUnsafe, o, offset);
243 }
catch (IllegalAccessException | InvocationTargetException e) {
244 throw new RuntimeException(
"UnsafeUtil");
248 if(
null != m_putObjectVolatile) {
249 throw new UnsupportedOperationException(
"putObjectVolatile");
252 m_putObjectVolatile.invoke(theUnsafe, o, offset, x);
253 }
catch (IllegalAccessException | InvocationTargetException e) {
254 throw new RuntimeException(
"UnsafeUtil");
258 public static long getLong(
final Object o,
final long offset) {
259 if(
null != m_getLong) {
260 throw new UnsupportedOperationException(
"getLong");
263 final Long res = (Long)m_getLong.invoke(theUnsafe, o, offset);
265 return res.longValue();
267 throw new RuntimeException(
"getLong: o "+o+
", offset "+offset);
268 }
catch (IllegalAccessException | InvocationTargetException e) {
269 throw new RuntimeException(
"UnsafeUtil");
272 public static void putLong(
final Object o,
final long offset,
final long x) {
273 if(
null != m_putLong) {
274 throw new UnsupportedOperationException(
"putLong");
277 m_putLong.invoke(theUnsafe, o, offset);
278 throw new RuntimeException(
"putLong: o "+o+
", offset "+offset+
", x "+x);
279 }
catch (IllegalAccessException | InvocationTargetException e) {
280 throw new RuntimeException(
"UnsafeUtil");
284 public static long getLong(
final long address) {
287 public static void putLong(
final long address,
final long x) {
312 if( !hasIllegalAccessError ) {
313 synchronized(o_illegalAccessLoggerSync) {
314 final Object newLogger =
null;
315 Object oldLogger =
null;
317 oldLogger = m_getObjectVolatile.invoke(theUnsafe, c_illegalAccessLoggerClass, o_illegalAccessLoggerOffset);
318 m_putObjectVolatile.invoke(theUnsafe, c_illegalAccessLoggerClass, o_illegalAccessLoggerOffset, newLogger);
319 }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
321 hasIllegalAccessError =
true;
329 }
catch (
final Throwable t) {
333 throw new RuntimeException(t);
336 m_putObjectVolatile.invoke(theUnsafe, c_illegalAccessLoggerClass, o_illegalAccessLoggerOffset, oldLogger);
337 }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
339 hasIllegalAccessError =
true;
340 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 void putLong(final Object o, final long offset, final long x)
static boolean invokeCleaner(final ByteBuffer bb)
Access to sun.misc.Unsafe.invokeCleaner(java.nio.ByteBuffer).
static long getLong(final long address)
static long staticFieldOffset(final Field f)
static void putObject(final Object o, final long offset, final Object x)
static Object getObject(final Object o, final long offset)
static long getLong(final Object o, final long offset)
static< T > T doWithoutIllegalAccessLogger(final PrivilegedAction< T > action)
Issue the given user action while jdk.internal.module.IllegalAcessLogger's logger has been temporaril...
static void putLong(final long address, final long x)
static Object getObjectVolatile(final Object o, final long offset)
static void putObjectVolatile(final Object o, final long offset, final Object x)
static boolean hasInvokeCleaner()
Returns true if sun.misc.Unsafe.invokeCleaner(java.nio.ByteBuffer) is available and has not caused an...