admin管理员组文章数量:1332971
I'm using FFM from first principles to access native structures, such as:
VkLayerProperties {
char layerName[256];
uint32_t specVersion;
uint32_t implementationVersion;
char description[256];
};
The following trivial code extracts the fields from a given off-heap memory address:
public void load(MemorySegment address) {
var layout = MemoryLayout.structLayout(
MemoryLayout.sequenceLayout(256, JAVA_BYTE).withName("layerName"),
JAVA_INT.withName("specVersion"),
JAVA_INT.withName("implementationVersion"),
MemoryLayout.sequenceLayout(256, JAVA_BYTE).withName("description")
);
VarHandle handle = layout.varHandle(PathElement.groupElement("specVersion"));
int specVersion = (int) handle.get(address, 0L);
....
}
This works fine for the primitive fields (and also for reference types). But how can the same pattern using the layout and path elements be used to create var handles to the array fields, i.e:
VarHandle layerName = layout.varHandle(...); // <-- magic here please
byte[] layerName = (byte[]) handle.get(address, 0L);
I have tried every combination of the various element classes, tried the helpers in MethodHandles
, etc. all without any luck.
Either the handle fails with a "not a value layout" error or the get
fails (presumably) because the coordinates are wrong. I suspect I'm just being more than normally dumb.
However, if one looks at the equivalent code generated using jextract
for this structure, lo and behold, it essentially doesn't use a var handle but just hard-codes the byte offsets and slices the memory:
public class VkLayerProperties {
public static MemorySegment layerName$slice(MemorySegment seg) {
return seg.asSlice(0, 256);
}
}
Whereas all the non-array fields use handles to access the fields directly:
static final VarHandle const$1 = constants$53.const$0.varHandle(MemoryLayout.PathElement.groupElement("specVersion"));
public static int specVersion$get(MemorySegment seg) {
return (int)constants$53.const$1.get(seg);
}
Obviously I could just use the same approach and calculate the byte offsets and sizes from the layout (or even just hard code them), but it seems like the using the path element framework was intended to be the preferred solution.
So:
Is there a way to access array fields by deriving a var handle from structures memory layout?
Why does the equivalent
jextract
circumvent the general approach and use a memory slice for these cases.
Are these two questions connected?
Note that "use jextract" is not an answer.
Thanks in advance for any suggestions or solutions.
I'm using FFM from first principles to access native structures, such as:
VkLayerProperties {
char layerName[256];
uint32_t specVersion;
uint32_t implementationVersion;
char description[256];
};
The following trivial code extracts the fields from a given off-heap memory address:
public void load(MemorySegment address) {
var layout = MemoryLayout.structLayout(
MemoryLayout.sequenceLayout(256, JAVA_BYTE).withName("layerName"),
JAVA_INT.withName("specVersion"),
JAVA_INT.withName("implementationVersion"),
MemoryLayout.sequenceLayout(256, JAVA_BYTE).withName("description")
);
VarHandle handle = layout.varHandle(PathElement.groupElement("specVersion"));
int specVersion = (int) handle.get(address, 0L);
....
}
This works fine for the primitive fields (and also for reference types). But how can the same pattern using the layout and path elements be used to create var handles to the array fields, i.e:
VarHandle layerName = layout.varHandle(...); // <-- magic here please
byte[] layerName = (byte[]) handle.get(address, 0L);
I have tried every combination of the various element classes, tried the helpers in MethodHandles
, etc. all without any luck.
Either the handle fails with a "not a value layout" error or the get
fails (presumably) because the coordinates are wrong. I suspect I'm just being more than normally dumb.
However, if one looks at the equivalent code generated using jextract
for this structure, lo and behold, it essentially doesn't use a var handle but just hard-codes the byte offsets and slices the memory:
public class VkLayerProperties {
public static MemorySegment layerName$slice(MemorySegment seg) {
return seg.asSlice(0, 256);
}
}
Whereas all the non-array fields use handles to access the fields directly:
static final VarHandle const$1 = constants$53.const$0.varHandle(MemoryLayout.PathElement.groupElement("specVersion"));
public static int specVersion$get(MemorySegment seg) {
return (int)constants$53.const$1.get(seg);
}
Obviously I could just use the same approach and calculate the byte offsets and sizes from the layout (or even just hard code them), but it seems like the using the path element framework was intended to be the preferred solution.
So:
Is there a way to access array fields by deriving a var handle from structures memory layout?
Why does the equivalent
jextract
circumvent the general approach and use a memory slice for these cases.
Are these two questions connected?
Note that "use jextract" is not an answer.
Thanks in advance for any suggestions or solutions.
Share Improve this question edited Nov 20, 2024 at 21:18 stridecolossus asked Nov 20, 2024 at 16:20 stridecolossusstridecolossus 1,56112 silver badges26 bronze badges 6 | Show 1 more comment1 Answer
Reset to default 1Is there a way to access array fields by deriving a var handle from structures memory layout?
No. This does not exist in the current FFM API.
VarHandles
have all kinds of atomic access modes, such as compareAndExchange
, that are not possible to implement for values larger than 8 bytes, due to hardware limitations.
Additionally, while you want a byte[]
copy to be returned, another user might want a long[]
(for improved alignment), or a MemorySegment
(reference or copy), or to be able to provide a pre-allocated array instead. There is no one obvious choice here.
So, working out the details is left up to the user. Instead, as jextract does, you have to create a slice of the memory you want to access, and then if you want that to be copied into a newly-allocated byte[]
, you can call toArray(ValueLayout.JAVA_BYTE)
on the resulting slice.
There are several ways to create a slice. As you've found out, jextract pre-computes the offset of the slice and calls asSlice
with that offset. Alternatively, you can use MemoryLayout::byteOffset
to derive the offset from a memory layout, then call asSlice
with the resulting offset. Or, as Rob Spoor mentioned in the comments, use MemoryLayout::sliceHandle
to create a method handle that will return a slice for the particular field.
本文标签: project panamaJava FFMObtaining a var handle to an array field of a structureStack Overflow
版权声明:本文标题:project panama - Java FFM - Obtaining a var handle to an array field of a structure - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1742345461a2457431.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
layout.sliceHandle
. But if you know the types, I think it's just as easy to usesegment.get(ValueLayout.JAVA_INT, layout.groupElement("specVersion"))
instead of usingVarHandle
. It prevents auto-(un)boxing. – Rob Spoor Commented Nov 20, 2024 at 16:310L
inhandle.get(address, 0L)
by wrapping the handle (once during creation) withMethodHandles.insertCoordinates(layout.varHandle(PathElement.groupElement("specVersion")), 1, 0L)
. – Rob Spoor Commented Nov 20, 2024 at 16:32insertCoordinates
trick but omitted it for brevity in the example code. The other suggestion for avoiding boxing is worth looking at though, cheers. – stridecolossus Commented Nov 20, 2024 at 17:05