FFM API: EA failure with 4+ address parameters

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Oct 23 16:21:46 UTC 2024


Thanks Ioannis, we'll take a look.

One thing that comes to mind is that when you pass an address to a 
downcall, the Linker has to keep its arena alive (to ensure it stays 
alive for the entire duration of the call). Now, if the segments you 
pass are constructed with MemorySegment::ofAddress, you get back 
segments associated with the global scope, so this "acquire" operation 
is a no-op.

But the Linker-generated code contains some non-trivial logic to try to 
reduce the number of acquire calls that are generated - e.g. if you pass 
7 arguments all associated with the same arena, we'll just do a single 
acquire. I wonder if, as the number of argument becomes increasingly 
big, the generated code for the downcall bindings becomes too complex 
and full of control flow, which then results in EA bailing out.

(Needless to say, we can't wait to make MemorySegment implementation a 
value class and avoid all these issues :-) )

If that is the issue, it might be that case that calling one acquire per 
pointer argument, even if redundant, leads to better optimizations than 
what we have now. The complex logic I'm referring to is here:

https://github.com/openjdk/jdk/blob/master/src/java.base/share/classes/jdk/internal/foreign/abi/BindingSpecializer.java#L497

Maurizio

On 23/10/2024 16:51, Ioannis Tsakpinis wrote:
> Hello,
>
> I've been migrating LWJGL to FFM and during testing of some real-world
> code (Vulkan rendering), I noticed a spike in GC activity with the FFM
> implementation, compared to the old JNI implementation. I think I've
> been able to track it down to what looks like an odd failure of escape
> analysis. Specifically, scalar replacement no longer occurs when
> calling functions with 4 or more ADDRESS (MemorySegment) parameters.
>
> JMH benchmark (you'll need to build a shared library with some empty
> functions and run with GC profiling enabled) that demonstrates the
> issue:
>
> https://gist.github.com/Spasi/71d5cfa687a1dbe95b3fce608d31ae6b
>
> There are functions with arity from 0 to 5. When invoking a downcall,
> raw pointer values are wrapped with MemorySegment.ofAddress() and
> passed to each argument. The exact pointer values do not matter.
>
> Until 3 ADDRESS parameters, or 3 ADDRESS parameters plus other non-
> ADDRESS parameters, everything is fine and there's no GC activity.
> With 4 or more ADDRESS parameters, allocations are no longer
> eliminated. The problem also occurs with a single MemorySegment that
> is passed to all parameters:
>
> var p = MemorySegment.ofAddress(42L);
> functionMH.invokeExact(p, p, p, p);
>
> Any idea what might be causing this?
>
> - Ioannis


More information about the panama-dev mailing list