28package com.jogamp.common.util;
30import java.lang.reflect.Field;
31import java.lang.reflect.InvocationTargetException;
32import java.lang.reflect.Method;
33import java.nio.Buffer;
34import java.nio.ByteBuffer;
35import java.security.PrivilegedAction;
37import com.jogamp.common.ExceptionUtils;
38import com.jogamp.common.nio.Buffers;
40import jogamp.common.Debug;
41import jogamp.common.os.PlatformPropsImpl;
48 static final boolean DEBUG;
50 DEBUG = Debug.debug(
"UnsafeUtil");
55 private static final Object theUnsafe;
56 private static final Method unsafeCleanBB;
57 private static volatile boolean hasUnsafeCleanBBError;
59 private static final Method m_getObject;
60 private static final Method m_putObject;
61 private static final Method m_getObjectVolatile;
62 private static final Method m_putObjectVolatile;
64 private static final Method m_getLong;
65 private static final Method m_putLong;
67 private static final Method m_staticFieldOffset;
68 private static final Method m_objectFieldOffset;
70 private static final Long addressFieldOffset;
72 private static final Class<?> c_illegalAccessLoggerClass;
73 private static final Long o_illegalAccessLoggerOffset;
74 private static final Object o_illegalAccessLoggerSync =
new Object();
75 private static volatile boolean hasIllegalAccessError;
78 final Object[] _theUnsafe = {
null };
79 final Method[] _cleanBB = {
null };
80 final Method[] _staticObjectFieldOffset = {
null,
null };
81 final Method[] _getPutObject = {
null,
null };
82 final Method[] _getPutObjectVolatile = {
null,
null };
83 final Method[] _getPutLong = {
null,
null };
84 final Long[] _addressFieldOffset = {
null };
85 final Class<?>[] _illegalAccessLoggerClass = {
null };
86 final Long[] _loggerOffset = {
null };
88 SecurityUtil.doPrivileged(
new PrivilegedAction<Object>() {
91 Class<?> unsafeClass =
null;
94 unsafeClass = Class.forName(
"sun.misc.Unsafe");
96 final Field f = unsafeClass.getDeclaredField(
"theUnsafe");
97 f.setAccessible(
true);
98 _theUnsafe[0] = f.get(
null);
100 _cleanBB[0] = unsafeClass.getMethod(
"invokeCleaner", java.nio.ByteBuffer.class);
101 _cleanBB[0].setAccessible(
true);
102 }
catch(
final Throwable t) {
104 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
107 if(
null != _theUnsafe[0] ) {
109 _getPutObject[0] = unsafeClass.getDeclaredMethod(
"getObject", Object.class,
long.class);
110 _getPutObject[1] = unsafeClass.getDeclaredMethod(
"putObject", Object.class,
long.class, Object.class);
111 }
catch(
final Throwable t) {
113 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
117 _getPutObjectVolatile[0] = unsafeClass.getDeclaredMethod(
"getObjectVolatile", Object.class,
long.class);
118 _getPutObjectVolatile[1] = unsafeClass.getDeclaredMethod(
"putObjectVolatile", Object.class,
long.class, Object.class);
119 }
catch(
final Throwable t) {
121 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
125 _getPutLong[0] = unsafeClass.getDeclaredMethod(
"getLong", Object.class,
long.class);
126 _getPutLong[1] = unsafeClass.getDeclaredMethod(
"putLong", Object.class,
long.class,
long.class);
127 }
catch(
final Throwable t) {
129 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
133 _staticObjectFieldOffset[0] = unsafeClass.getDeclaredMethod(
"staticFieldOffset", Field.class);
134 _staticObjectFieldOffset[1] = unsafeClass.getDeclaredMethod(
"objectFieldOffset", Field.class);
135 }
catch(
final Throwable t) {
137 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
140 if(
null != _staticObjectFieldOffset[1] ) {
143 final Field f = Buffer.class.getDeclaredField(
"address");
144 _addressFieldOffset[0] = (Long)_staticObjectFieldOffset[1].invoke(_theUnsafe[0], f);
145 }
catch(
final Throwable t) {
147 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
151 if( PlatformPropsImpl.JAVA_9 &&
null != _staticObjectFieldOffset[0] ) {
153 _illegalAccessLoggerClass[0] = Class.forName(
"jdk.internal.module.IllegalAccessLogger");
154 final Field loggerField = _illegalAccessLoggerClass[0].getDeclaredField(
"logger");
155 _loggerOffset[0] = (Long) _staticObjectFieldOffset[0].invoke(_theUnsafe[0], loggerField);
156 }
catch(
final Throwable t) {
158 ExceptionUtils.dumpThrowable(
"UnsafeUtil", t);
165 theUnsafe = _theUnsafe[0];
166 unsafeCleanBB = _cleanBB[0];
167 hasUnsafeCleanBBError =
null == theUnsafe ||
null == unsafeCleanBB;
169 System.err.println(
"UnsafeUtil.init: hasTheUnsafe: "+(
null!=theUnsafe)+
", hasInvokeCleaner: "+!hasUnsafeCleanBBError);
171 m_staticFieldOffset = _staticObjectFieldOffset[0];
172 m_objectFieldOffset = _staticObjectFieldOffset[1];
173 addressFieldOffset = _addressFieldOffset[0];
174 m_getObject = _getPutObject[0];
175 m_putObject = _getPutObject[1];
176 m_getObjectVolatile = _getPutObjectVolatile[0];
177 m_putObjectVolatile = _getPutObjectVolatile[1];
178 m_getLong = _getPutLong[0];
179 m_putLong = _getPutLong[1];
180 c_illegalAccessLoggerClass = _illegalAccessLoggerClass[0];
181 o_illegalAccessLoggerOffset = _loggerOffset[0];
182 hasIllegalAccessError =
null == m_getObjectVolatile ||
null == m_putObjectVolatile ||
183 null == c_illegalAccessLoggerClass ||
null == o_illegalAccessLoggerOffset;
185 System.err.println(
"UnsafeUtil.init: hasUnsafeIllegalAccessLogger: "+!hasIllegalAccessError);
206 if( hasUnsafeCleanBBError || !bb.isDirect() ) {
210 unsafeCleanBB.invoke(theUnsafe, bb);
212 }
catch(
final Throwable t) {
213 hasUnsafeCleanBBError =
true;
222 if(
null != m_staticFieldOffset) {
223 throw new UnsupportedOperationException(
"staticFieldOffset");
226 final Long res = (Long)m_staticFieldOffset.invoke(theUnsafe, f);
228 return res.longValue();
230 throw new RuntimeException(
"staticFieldOffset: f "+f);
231 }
catch (IllegalAccessException | InvocationTargetException e) {
232 throw new RuntimeException(
"UnsafeUtil");
236 if(
null != m_objectFieldOffset) {
237 throw new UnsupportedOperationException(
"objectFieldOffset");
240 final Long res = (Long)m_objectFieldOffset.invoke(theUnsafe, f);
242 return res.longValue();
244 throw new RuntimeException(
"objectFieldOffset: f "+f);
245 }
catch (IllegalAccessException | InvocationTargetException e) {
246 throw new RuntimeException(
"UnsafeUtil");
250 public static Object
getObject(
final Object o,
final long offset) {
251 if(
null != m_getObject) {
252 throw new UnsupportedOperationException(
"getObject");
255 return m_getObject.invoke(theUnsafe, o, offset);
256 }
catch (IllegalAccessException | InvocationTargetException e) {
257 throw new RuntimeException(
"UnsafeUtil: o "+o+
", offset "+offset, e);
260 public static void putObject(
final Object o,
final long offset,
final Object x) {
261 if(
null != m_putObject) {
262 throw new UnsupportedOperationException(
"putObject");
265 m_putObject.invoke(theUnsafe, o, offset, x);
266 }
catch (IllegalAccessException | InvocationTargetException e) {
267 throw new RuntimeException(
"UnsafeUtil");
272 if(
null != m_getObjectVolatile) {
273 throw new UnsupportedOperationException(
"getObjectVolatile");
276 return m_getObjectVolatile.invoke(theUnsafe, o, offset);
277 }
catch (IllegalAccessException | InvocationTargetException e) {
278 throw new RuntimeException(
"UnsafeUtil");
282 if(
null != m_putObjectVolatile) {
283 throw new UnsupportedOperationException(
"putObjectVolatile");
286 m_putObjectVolatile.invoke(theUnsafe, o, offset, x);
287 }
catch (IllegalAccessException | InvocationTargetException e) {
288 throw new RuntimeException(
"UnsafeUtil");
292 public static long getLong(
final Object o,
final long offset) {
293 if(
null != m_getLong) {
294 throw new UnsupportedOperationException(
"getLong");
297 final Long res = (Long)m_getLong.invoke(theUnsafe, o, offset);
299 return res.longValue();
301 throw new RuntimeException(
"getLong: o "+o+
", offset "+offset);
302 }
catch (IllegalAccessException | InvocationTargetException e) {
303 throw new RuntimeException(
"UnsafeUtil");
306 public static void putLong(
final Object o,
final long offset,
final long x) {
307 if(
null != m_putLong) {
308 throw new UnsupportedOperationException(
"putLong");
311 m_putLong.invoke(theUnsafe, o, offset);
312 throw new RuntimeException(
"putLong: o "+o+
", offset "+offset+
", x "+x);
313 }
catch (IllegalAccessException | InvocationTargetException e) {
314 throw new RuntimeException(
"UnsafeUtil");
318 public static long getLong(
final long address) {
321 public static void putLong(
final long address,
final long x) {
326 if(
null == buffer ) {
329 if(
null != addressFieldOffset ||
null != m_getLong ) {
332 return getLong(buffer, addressFieldOffset.longValue());
356 if( !hasIllegalAccessError ) {
357 synchronized(o_illegalAccessLoggerSync) {
358 final Object newLogger =
null;
359 Object oldLogger =
null;
361 oldLogger = m_getObjectVolatile.invoke(theUnsafe, c_illegalAccessLoggerClass, o_illegalAccessLoggerOffset);
362 m_putObjectVolatile.invoke(theUnsafe, c_illegalAccessLoggerClass, o_illegalAccessLoggerOffset, newLogger);
363 }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
365 hasIllegalAccessError =
true;
373 }
catch (
final Throwable t) {
377 throw new RuntimeException(t);
380 m_putObjectVolatile.invoke(theUnsafe, c_illegalAccessLoggerClass, o_illegalAccessLoggerOffset, oldLogger);
381 }
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
383 hasIllegalAccessError =
true;
384 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 java.nio.Buffer manipulations.
static long getDirectBufferAddress(final Object directBuffer)
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 objectFieldOffset(final Field f)
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 long getDirectBufferAddress(final Buffer buffer)
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...