A few considerations (mostly) on jextract

Markus Knetschke markus.knetschke at gmail.com
Mon May 17 18:14:16 UTC 2021

On 17/5/2021 11:54, Maurizio Cimadamore wrote:
> > 1) the classes for structs jextract generates don't feel very oo to
> > me. I would like to see a class with constructor and getter/setter
> > methods encapsulating the MemorySegment.
> I hear you - this is indeed possible, at the cost of more allocation.
> For now we have tried to stick to a principle that jextract should not
> add overhead, but I tend to agree that, in the case of struct, this ends
> up being punitive at times (especially when you have structs nested
> inside structs nested inside structs).
> I believe at some point some other experiment will be made to make
> struct handling more OO (as you say), and, if we can get some help from
> Valhalla primitive types, maybe we won't even pay a performance price!
Don't get me wrong, I don't suggest removing the
public static  MemoryAddress xxx$get(MemorySegment seg)
accessors but add a MemorySegment field, a constructor, and accessors.
So everyone can choose if one uses the static methods or calls the constructor.
Bonus Points if jextract generates additional downcalls extracting the
MemorySegment from wrapper objects and upcall wrapper calling
the constructor of the wrapper objects.
I've tried a simple annotation processor which works well
when there is a solution for 2). So it's not the highest priority
and I guess we get at least 2 release cycles before jextract
reaches preview status. Enough time to experiment with multiple variants.

> > 2) there is no public interface to get the FunctionDescriptor and the
> > MethodType of callbacks. (ok the MethodType could get extracted by
> > Reflection from the generated interface) If you start with a
> > MethodHandle already you have to either wrap it with
> > MethodHandleProxies.asInterfaceInstance or writing the already
> > existing information into your written code. I would like to see a
> > getter for the MethodType and a method registering a method handle as
> > a callback (something like static MemorySegment allocate(MethodHandle
> > mh)) or two getters for MethodType and FunctionDescriptor.
> These can be easily added - basically, you are in the situation where
> you already have a method handle, and so functional interfaces work
> _against_ you. Got it.
Yes especially with a wrapper generator mentioned all the converting parts
could be done with method handles resulting in very fast code but
getting the FD is very hard if you don't want to guess how the field in
<xxx>_constants_<highestNum> is named and force adding
open in the module-info file. Btw it would be great if jextract could
generate a module-info.java itself.

> > 3) I often encounter fixed-length arrays in structs holding stings.
> > The best way I've found to extract them safely is to first get the
> > start offset of the string with MemoryLayout.byteOffset(path) then
> > extracting the size of the struct field with
> > MemoryLayout.select(path).byteSize() and reading the string with
> > CLinker.toJavaString(struct.asSlice(offset, size)) this is very bulky
> > for simple things like putting ten strings from a struct into a
> > record. I would like to see a simpler way for this for example a
> > MemorySegment.asSlice(MemoryLayout, PathElement...) method. (This
> > would be handy too for byte array struct fields.
> In the new API, we have a new method in MemoryLayout like this:
> default MethodHandle sliceHandle(PathElement... elements) {
> Which I think does what you want?
It looks a bit better than my own public static asSlice method but I'm not sure
if a task simple as reading a fixed-length string of a struct should
be as long as
or reading a fixed number of bytes
having a
MethodHandle(MemorySegment, PathElement...)MemorySegment
would be more useful because you could .bindTo() the struct and access multiple
fields through it. Bringing the aboth example to:
var getSlice = getSubvolInfoIoctlArgs.sliceHandle().bindTo(ioctlArg)
CLinker.toJavaString((MemorySegment) getSlice.invoke(groupElement("name"))
((MemorySegment) getSlice.invoke(groupElement("parent_uuid"))).toByteArray()

But with this, the needed cast and the try {} catch (Throwable ignored) {}
remain and are looking very ugly in my mind.
On the other hand, it's only a problem if you don't want to use jextract.

Best regards,
Markus Knetschke

More information about the panama-dev mailing list