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:
Norman Maurer 2017-02-16 15:36:10 +01:00
parent 3fa3709005
commit d57d041f48
2 changed files with 44 additions and 42 deletions

View File

@ -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();
}

View File

@ -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) {