Reputation: 33
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.
Upvotes: 3
Views: 140
Reputation: 198391
You should not be trying to access the address or array of ByteBuffers. That's still unsafe, and there's a reason they're removing Unsafe.
You should be using byteBufferViewVarHandle
to replace the places where you use unsafe accessors of the byte buffer.
This allows you to do the important things you might have done with the unsafe access to the address and buffer fields. If that doesn't satisfy your needs, then what you should be doing is asking how to replace that with VarHandle instead of using these functions.
You should definitely not have to open any modules.
Upvotes: 1
Reputation: 9175
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));
Upvotes: 1