Use Unsafe to read ByteBuffer.address field to make it work on Java9 as well.
Motivation: Java9 does not allow changing access level via reflection by default. This lead to the situation that netty disabled Unsafe completely as ByteBuffer.address could not be read. Modification: Use Unsafe to read the address field as this works on all Java versions. Result: Again be able to use Unsafe optimisations when using Netty with Java9
This commit is contained in:
parent
3fa3709005
commit
d57d041f48
@ -27,7 +27,8 @@ public class WrappedUnpooledUnsafeByteBufTest extends BigEndianUnsafeDirectByteB
|
||||
@Before
|
||||
@Override
|
||||
public void init() {
|
||||
Assume.assumeTrue("sun.misc.Unsafe not found, skip tests", PlatformDependent.hasUnsafe());
|
||||
Assume.assumeTrue("PlatformDependent.useDirectBufferNoCleaner() returned false, skip tests",
|
||||
PlatformDependent.useDirectBufferNoCleaner());
|
||||
super.init();
|
||||
}
|
||||
|
||||
|
@ -51,49 +51,16 @@ final class PlatformDependent0 {
|
||||
|
||||
static {
|
||||
final ByteBuffer direct;
|
||||
final Field addressField;
|
||||
Field addressField = null;
|
||||
Unsafe unsafe;
|
||||
|
||||
if (PlatformDependent.isExplicitNoUnsafe()) {
|
||||
direct = null;
|
||||
addressField = null;
|
||||
unsafe = null;
|
||||
} else {
|
||||
direct = ByteBuffer.allocateDirect(1);
|
||||
// attempt to access field Buffer#address
|
||||
final Object maybeAddressField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
try {
|
||||
final Field field = Buffer.class.getDeclaredField("address");
|
||||
Throwable cause = ReflectionUtil.trySetAccessible(field);
|
||||
if (cause != null) {
|
||||
return cause;
|
||||
}
|
||||
// if direct really is a direct buffer, address will be non-zero
|
||||
if (field.getLong(direct) == 0) {
|
||||
return null;
|
||||
}
|
||||
return field;
|
||||
} catch (IllegalAccessException e) {
|
||||
return e;
|
||||
} catch (NoSuchFieldException e) {
|
||||
return e;
|
||||
} catch (SecurityException e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (maybeAddressField instanceof Field) {
|
||||
addressField = (Field) maybeAddressField;
|
||||
logger.debug("java.nio.Buffer.address: available");
|
||||
} else {
|
||||
logger.debug("java.nio.Buffer.address: unavailable", (Throwable) maybeAddressField);
|
||||
addressField = null;
|
||||
}
|
||||
}
|
||||
|
||||
Unsafe unsafe;
|
||||
if (addressField != null) {
|
||||
// attempt to access field Unsafe#theUnsafe
|
||||
final Object maybeUnsafe = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
@ -156,12 +123,46 @@ final class PlatformDependent0 {
|
||||
logger.debug("sun.misc.Unsafe.copyMemory: unavailable", (Throwable) maybeException);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If we cannot access the address of a direct buffer, there's no point of using unsafe.
|
||||
// Let's just pretend unsafe is unavailable for overall simplicity.
|
||||
unsafe = null;
|
||||
}
|
||||
|
||||
if (unsafe != null) {
|
||||
final Unsafe finalUnsafe = unsafe;
|
||||
|
||||
// attempt to access field Buffer#address
|
||||
final Object maybeAddressField = AccessController.doPrivileged(new PrivilegedAction<Object>() {
|
||||
@Override
|
||||
public Object run() {
|
||||
try {
|
||||
final Field field = Buffer.class.getDeclaredField("address");
|
||||
// Use Unsafe to read value of the address field. This way it will not fail on JDK9+ which
|
||||
// will forbid changing the access level via reflection.
|
||||
final long offset = finalUnsafe.objectFieldOffset(field);
|
||||
final long address = finalUnsafe.getLong(direct, offset);
|
||||
|
||||
// if direct really is a direct buffer, address will be non-zero
|
||||
if (address == 0) {
|
||||
return null;
|
||||
}
|
||||
return field;
|
||||
} catch (NoSuchFieldException e) {
|
||||
return e;
|
||||
} catch (SecurityException e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (maybeAddressField instanceof Field) {
|
||||
addressField = (Field) maybeAddressField;
|
||||
logger.debug("java.nio.Buffer.address: available");
|
||||
} else {
|
||||
logger.debug("java.nio.Buffer.address: unavailable", (Throwable) maybeAddressField);
|
||||
|
||||
// If we cannot access the address of a direct buffer, there's no point of using unsafe.
|
||||
// Let's just pretend unsafe is unavailable for overall simplicity.
|
||||
unsafe = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
UNSAFE = unsafe;
|
||||
|
||||
if (unsafe == null) {
|
||||
|
Loading…
Reference in New Issue
Block a user