I've had a hard time removing usages of Unsafe and replacing with either VarHandle
or MemorySegment
/MemoryLayout
. The goal is to remove usages of Unsafe and replace with nondeprecated API's.
Two examples are:
private static long methodA(Buffer x) {
return UNSAFE.getLong(x, addressFieldOffset);
}
and
private static Object methodB(ByteBuffer x) {
return UNSAFE.getObject(x, hbFieldOffset);
}
Firstly, creating the right VarHandle
or MemorySegment
has been a challenge. It seems when I end up using the documentation's suggested "Use VarHandle.get()
or MemorySegment.get(ValueLayout.ofLong, long)
" I end up with a WrongMethodTypeException
or a different result than before that breaks current tests, etc. Can I get some help on the appropriate use?
I've tried:
MemorySegment segment = MemorySegment.ofBuffer(x);
long result = segment.get(ValueLayout.ofLong, int offset) // I've tried several different layouts and different offsets,
either getting a WrongMethodTypeException
or an incompatible offset error
Also tried:
MemorySegment segment = MemorySegment.ofArray(new long[10]); // also tried with byte[10] and int[10]
With varHandle I've tried:
VarHandle handle = MethodHandles.arrayElementVarHandle(long[].class); \\ also tried byte[].class, int[].class, and long[].class
Buffer bufferField = Buffer.allocate(16)
VarHandle handle = MethodHandles.lookup().findStaticVarHandle(ClassIAmIn.class, "bufferField", Buffer.class);
Usually get a Cannot convert MethodHandles(VarHandle, Buffer, long) to (VarHandle)Buffer
or something along those lines.
I'm assuming that addressFieldOffset
is the offset of field address
of class java.nio.Buffer
, and hbFieldOffset
is the offset of field hb
of class java.nio.ByteBuffer
.
You're trying to access private fields. That means you need a private method lookup first:
MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(Buffer.class, MethodHandles.lookup());
You need to open package java.nio
of module java.base
to your module (ALL-UNNAMED
if your module is unnamed), or you'll get an exception:
Exception java.lang.IllegalAccessException: module java.base does not open java.nio to unnamed module @7e0b0338
at MethodHandles.privateLookupIn (MethodHandles.java:279)
Now you can lookup the var handles:
VarHandle addressHandle = lookup.findVarHandle(Buffer.class, "address", long.class);
long address = (long) addressHandle.get(buffer);
System.out.printf("%d%n", address);
VarHandle hbHandle = lookup.findVarHandle(ByteBuffer.class, "hb", byte[].class);
byte[] hb = (byte[]) hbHandle.get(buffer);
System.out.printf("%s%n", Arrays.toString(hb));