RFR: 8338677: Improve startup of memory access var handles by simplifying combinator chains [v2]
Claes Redestad
redestad at openjdk.org
Wed Aug 21 10:15:04 UTC 2024
On Wed, 21 Aug 2024 09:38:42 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:
>> This PR reduces the amount of lambda forms (LFs) which are created when generating var handles for simple struct field accessors. This contributes to the startup regression seen in [JDK-8337505](https://bugs.openjdk.org/browse/JDK-8337505).
>>
>> There are essentially three sources of excessive var handle adaptation:
>>
>> 1. `LayoutPath::dereferenceHandle` has to do some very complex adaptation (including a permute) in order to inject alignment and size checks (against the enclosing layout) on the generated var handle.
>> 2. Even in simple cases (e.g. when there's no dynamic coordinate), the offset of the accessed field is added to the var handle via an expensive collect adapter.
>> 3. When we adapt a `long` var handle to work on `MemorySegment` using an `AddressLayout`, we make no distinction on whether the address layout has a target layout or not. In the latter case (common!) we can adapt more simply.
>>
>> The meat of this PR is to address (1) by changing the shape of the generated helpers in the `X-VarHandleSegmentView.java.template` class. That is, the method for doing a plain get will now have the following shape:
>>
>>
>> T get(MemorySegment segment, MemoryLayout enclosing, long base, long offset)
>>
>>
>> Where:
>> * `segment` is the segment being accessed
>> * `enclosing` is the enclosing layout (the root of the selected layout path) against which to check size and alignment
>> * `base` is the public-facing offset passed by the user when calling `get` on the var handle
>> * `offset` is the offset at which the selected layout element can be found from the root (this can be replaced with an expression that takes several dynamic indices and turn them into a single offset)
>>
>> With this organization, it is easy to see how, in order to create a memory access var handle for a struct field `S.f` we only need to:
>> * inject the enclosing layout `S` into the var handle (into the `enclosing` coordinate)
>> * inject the offset of `S.f` into the var handle (into the `offset` coordinate)
>>
>> This way, we get our plain old memory access var handle featuring only two coordinates: a segment and an offset. Note how, to get there, we only needed very simple adaptations (e.g. `MethodHandles::insertCoordinates`).
>>
>> #### Evaluation
>>
>> I did some tests using the benchmark in [JDK-8337505](https://bugs.openjdk.org/browse/JDK-8337505) to assess the impact of this change on startup. To evaluate startup, I ran the benchmark 50 times and then took some stats. Here's what the...
>
> Maurizio Cimadamore has updated the pull request incrementally with one additional commit since the last revision:
>
> Address review comment
> Clarify code comment
LGTM.
Some of the new and pre-existing static MHs in `Utils` and other places look like they are used conditionally and are likely candidates to be `StableValue`s once available.
-------------
Marked as reviewed by redestad (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/20647#pullrequestreview-2250385822
More information about the core-libs-dev
mailing list