On Mon, 25 Aug 2025 09:11:06 GMT, Marc Chevalier <mcheval...@openjdk.org> wrote:

>> First, credit to @TobiHartmann for the diagnostic, and a lot of the solution.
>> 
>> # Diagnostic
>> 
>> According to [Strict Field Initialization 
>> JEP](https://openjdk.org/jeps/8350458), when a strict field is being 
>> initialized, it is not quite immutable, but observally immutable: at first, 
>> the field can be only set (during the early larval phase), then it can be 
>> only read (late larval or initialized phase), so the last set is the actual 
>> value one can ever observe.
>> 
>> The interesting part is that in early larval phase, a field can be subject 
>> to some side effects. When applied to a value object, that means that until 
>> it reaches the unrestricted state, it is not yet immutable. While being not 
>> theoretically necessary, avoiding scalarization and keeping the value object 
>> behind a reference is a convenient way to make sure that side effects are 
>> correctly applied. This strategy means that we shouldn't scalarized before 
>> reaching the unrestricted state. Normally, in C2, finding out what is early 
>> larval or not is the job of bytecode parsing, but in OSR compilation, 
>> everything about the StartOSR is not parsed, and thus some objects are 
>> soundly assumed that they might be larval, when they actually aren't. In the 
>> reported example, that leads to drastic performance difference between OSR 
>> and non OSR compilation: the second one is able to eliminate allocations 
>> since it knows more precisely when the value object can be scalarized.
>> 
>> In the original example:
>> 
>> public value class MyNumber {
>>     private long d0;
>>     private MyNumber(long d0) { this.d0 = d0; }
>>     public MyNumber add(long v) { return new MyNumber(d0 + v); }
>> 
>>     private static void loop() {
>>         MyNumber dec = new MyNumber(123);
>>         for (int i = 0; i < 1_000_000_000; ++i) {
>>             dec = dec.add(i);
>>         }
>>     }
>> 
>>     public static void main(String[] args) {
>>         for (int i = 0; i < 10; ++i) {
>>             loop();
>>         }
>>     }
>> }
>> 
>> OSR happens in the loop in `loop`, but here `dec` is not detected to be 
>> unrestricted (so immutable, so scalarizable), so the allocation in inlined 
>> `add` still needs to happen because we need the buffer for the new `dec`. 
>> The first iteration traps at the exit of the loop (unstable if), OSR happens 
>> again, followed by a non-OSR compilation, finding correctly that `dec` can 
>> be scalarized in the loop, making the third iteration fast.
>> 
>> # Solution
>> 
>> Overall, the solution requires to improve our detection of early larval va...
>
> Marc Chevalier has updated the pull request incrementally with two additional 
> commits since the last revision:
> 
>  - Rephrase summary
>  - +copyright

test/hotspot/jtreg/compiler/valhalla/inlinetypes/LarvalDetectionAboveOSR.java 
line 30:

> 28:  * state of value objects coming from above the OSR start, and not 
> consider
> 29:  * everything as potentially early larval. Value objects that are known 
> to be
> 30:  * unrestricted (late larval of fully initialized) are immutable, and can 
> be

Typo? 

Suggestion:

 * unrestricted (late larval or fully initialized) are immutable, and can be

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

PR Review Comment: 
https://git.openjdk.org/valhalla/pull/1531#discussion_r2297587571

Reply via email to