On Wed, 18 Oct 2023 20:08:26 GMT, Phil Race <[email protected]> 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