RFR: 7903947: Access to function pointers in structs could be streamlined

Duncan Gittins duncan.gittins at gmail.com
Thu Jul 24 13:49:50 UTC 2025


This proposal makes it nicer to handle invokers.  I generated my code with
this change but as you'vr noted it does indeed lead to clashes using the
proposed naming convention.
My  Windows COM apps run fine once I'd commented out a few of the clashing
setters that I don't use, such as:

//    public static void Release(MemorySegment struct, MemorySegment
fieldValue) {
//        struct.set(Release$LAYOUT, Release$OFFSET, fieldValue);
//    }
    public static int Release(MemorySegment struct, MemorySegment _x0) {
        MemorySegment fp = struct.get(Release$LAYOUT, Release$OFFSET);
        return Release.invoke(fp, _x0);
    }

Will the use of ",functional" be the intended way to trigger this
enhancement? I wonder whether last error capture could be built in with
"--include-function funcname,erro" or  "--include-function
funcname,GetLastError"

Kind regards

Duncan

On Thu, 24 Jul 2025 at 10:29, Maurizio Cimadamore <mcimadamore at openjdk.org>
wrote:

> On Wed, 23 Jul 2025 12:37:47 GMT, Nizar Benalla <nbenalla at openjdk.org>
> wrote:
>
> > Please review this patch to add a new option where you can generate an
> direct invoker methods. This feature is intended to be used on structs that
> are just a collection of functions we had like to call.
> >
> > If this feature is used, we remove the getter to avoid name collisions
> as we assume this is similar to an interface.
> >
> > Changes to `GUIDE.md` have been intentionally left out from this initial
> patch to make reviews easier.
> >
> >
> > struct Foo {
> >     struct Bar (*a)(void);
> >     struct Bar (*b)(int);
> > };
> >
> >
> > Before
> >
> >
> > var foo = alloc_callback_h.foo();
> >
> > var barA = Foo.a.invoke(Foo.a(foo), arena);
> > var barB = Foo.b.invoke(Foo.b(foo), arena, 100);
> >
> >
> > After
> >
> >
> > var foo = alloc_callback_h.foo();
> >
> > var barA = Foo.a(foo, arena);
> > var barB = Foo.b(foo, arena, 100);
>
> Just to recap solution we have explored previously.
>
> It would be nice if, in principle, just doing this:
>
>
> var bar = Foo.a(foo, <args>);
>
>
> worked, and it invoked the correct function pointer on the `foo` struct.
> But this solution can lead to clashes. Specifically, if the function
> pointer takes no arguments, then `Foo.a(foo)` would look exactly like a
> struct getter.
>
> Another solution would be to tweak `a::invoke` method to work on a `foo`
> instance directly, and not on the _address_ that function takes. But this
> breaks composition -- if you first obtain the function pointer (a
> MemorySegment) stored at `Foo::a`, and then want to invoke it at a later
> point, how would you do it? If `invoke` takes a segment for `Foo` you can't
> really -- you always need to _first_ store the address in the `Foo` struct,
> and _then_ call the desired function pointer using `a::invoke`. Which seems
> awkward.
>
> (note also that we cannot "just" add an overload of `a::invoke` that takes
> a Foo, because that is a memory segment too, so we get another clash).
>
> In other words, there's no "easy" solution here. One possibility might be
> to add an invoker accessor to `Foo` -- something like
> `Foo.a$invoke(<args>)`. Since this uses a different name there would be no
> clash with the getter. This leaves the problem that, in structs that
> contain only function pointers, the getters are probably not very useful,
> but maybe we can add logic to filter those out.
>
> The other solution is the one explored here: the developer _knows_ this
> isn't just _any_ struct, but a "functional" struct. It tells jextract, and
> jextract reacts by generating slightly different code. Perhaps one issue
> with this approach (although we arrived at it honestly) is that if one
> stares at code like:
>
>
> var barA = Foo.a(<args>);
>
>
> It is pretty difficult to tell whether that's a getter/setter or an
> "invoker".
>
> src/main/java/org/openjdk/jextract/impl/StructBuilder.java line 160:
>
> > 158:             boolean isFuncPtr = functionalDispatch &&
> Utils.isFunctionPointer(type);
> > 159:             if (isFuncPtr) {
> > 160:                 emitFieldSetter(javaName, varTree, layoutField,
> offsetField);
>
> I'm not sure we even want the setter -- the fields in these structs are
> typically populated by a library
>
> src/main/java/org/openjdk/jextract/impl/StructBuilder.java line 180:
>
> > 178:      * Generates exactly one invoker, inlining the struct.get(...)
> to avoid name collision.
> > 179:      */
> > 180:     private void emitFunctionalConvenience(String invokerName,
>
> I'd call this `emitInvoker`
>
> -------------
>
> PR Comment:
> https://git.openjdk.org/jextract/pull/287#issuecomment-3112725685
> PR Review Comment:
> https://git.openjdk.org/jextract/pull/287#discussion_r2227973060
> PR Review Comment:
> https://git.openjdk.org/jextract/pull/287#discussion_r2227971894
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/jextract-dev/attachments/20250724/72274e5f/attachment.htm>


More information about the jextract-dev mailing list