RFR: 8318364: Add an FFM-based implementation of harfbuzz OpenType layout

Jorn Vernee jvernee at openjdk.org
Wed Oct 18 23:47:47 UTC 2023


On Wed, 18 Oct 2023 20:08:26 GMT, Phil Race <prr at openjdk.org> wrote:

>> Requiring users to specify the size of the sequence layout was done in order to dispel the illusion that there was any kind of special handling for a sequence layout created without a size. e.g. if you try to allocate with it, what should happen? Should we detect that this as a special case? Or just crush with an OOME? This is something other users ran into in practice, and removing the size-less factory revealed some latent bugs in the tests as well. So, I feel that overall, dropping the size-less factory was the right move. This was more or less an orthogonal decision to the decision of adding the base offset parameter.
>> 
>> The previous JDK 21 API asked users to construct layouts for memory of which they did not know the layout in advance. e.g. when creating a var handle from a sequence layout with the maximum number of elements, the in-memory array that is being accessed is likely not actually an array with the maximum number of elements? The special max element sequence layout is just a workaround used to be able to create an indexed var handle.
>> 
>> Another example is a 2-dimensional matrix with a dynamic row and column size. How should this be represented using a memory layout? We can't use the max element sequence layout trick in that case, since the size of the inner sequence affects the scaling of the index for the outer sequence.
>> 
>> The core issue is that, to get good performance, a user needs to construct the layout and derive var handles in advance, but at the same time it is not possible to represent a layout with a 'dynamic' size. We went back and forth on ideas in order to add better support for dynamic sizes in the layout API. But in the end, all the things we tried ended up being convoluted, and had their own set of corner cases that were ill-addressed.
>> 
>> So, the conclusion we arrived at was that layouts are better left alone, and should only be used to represent memory layouts that are 'static'/fixed and known up front. In that case a user can declare the layout, and all the var handles they need, in advance, and stick them into `static final` fields, which is required to get good performance.
>> 
>> But then the question becomes: what about structural access to memory whose layout can _not_ be represented statically? Even in those cases, often there is a part of the structure of the memory layout that is fixed, and part of the layout that is dynamic. The memory layout API can still be used for the fixed part, and then the extra bas...
>
> I feel like I'm starting to learn that once you've got your VarHandle from FFM, you need to head over to java.lang.invoke and hunt around to see what tricks you can do with it.
> The less I have to do that the better.

I wouldn't say it's necessarily required, but I would say that it is what ultimately leads to the most succinct code. I'm probably biased towards using the java.lang.invoke tricks though.

The java.lang.invoke combinator API is a convenient way to generate wrapper functions around a VarHandle (or MethodHandle). But, you could also write out the wrapper functions manually. In this case that shouldn't be too much of a problem given that the code only uses `get`. You could declare basic field VarHandles created with `layout.varHandle(PathElement.groupElement(name));`, and then write the wrapper functions like so:


public static int getYOffset(MemorySegment glyphPosArr, int index) {
    long posArrOffset = PositionLayout.scale(0, index); // or just: index * PositionLayout.byteSize()
    return (int) y_offsetHandle.get(glyphPosArr, posArrOffset);
}


You would need 6 of these in total. Or, just use the implementation 'inline', without the wrapper functions.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/15476#discussion_r1364697148


More information about the core-libs-dev mailing list