On Mon, 14 Apr 2025 18:09:35 GMT, Chen Liang <li...@openjdk.org> wrote:

>> Hello Per, I'm not too familiar with runtime compiler optimizations. So 
>> consider this as a basic question. 
>> 
>>> This means the VM can trust these fields to never change which enables 
>>> constant folding optimizations.
>> 
>> If I'm not wrong, then it is the `hash` field value that we want to be 
>> considered as a constant (once computed) so that calls to 
>> `String.hashCode()` would get replaced with the constant computed value.
>> 
>> Looking at the current implementation of `String.hashCode()`:
>> 
>> 
>> public int hashCode() {
>>         // The hash or hashIsZero fields are subject to a benign data race,
>>         // making it crucial to ensure that any observable result of the
>>         // calculation in this method stays correct under any possible read 
>> of
>>         // these fields. Necessary restrictions to allow this to be correct
>>         // without explicit memory fences or similar concurrency primitives 
>> is
>>         // that we can ever only write to one of these two fields for a given
>>         // String instance, and that the computation is idempotent and 
>> derived
>>         // from immutable state
>>         int h = hash;
>>         if (h == 0 && !hashIsZero) {
>>             h = isLatin1() ? StringLatin1.hashCode(value)
>>                            : StringUTF16.hashCode(value);
>>             if (h == 0) {
>>                 hashIsZero = true;
>>             } else {
>>                 hash = h;
>>             }
>>         }
>>         return h;
>>     }
>> 
>> 
>> If I'm reading that correctly, and keeping aside concurrent calls from this 
>> discussion, then only one of `hash` or the `hashIsZero` fields will have its 
>> value changed to a non-default value. i.e. if `hashCode()` implementation 
>> computes a non-zero value then the `hash` field will be assigned a 
>> (non-default) value and if that method computes a hash of 0, then 
>> `hashIsZero` will get assigned a (non-default) value. It then means that the 
>> other field will never move out of its initial value and thus will never be 
>> considered "stable".
>> 
>> Am I right? If yes, then would the runtime (hotspot) compiler still replace 
>> the call to `String.hashCode()` with a constant value?
>
> Also re @jaikiran: yes, you are right that the current code cannot 
> constant-fold the scenario where the hash is 0; so `"".hashCode()` is not 
> constant as a result. The solution I shared above can address this scenario, 
> but it cannot completely bring performance to parity with other 
> constant-folded cases in Remi's shared benchmark (see 
> https://github.com/liachmodded/jdk/commit/247e8bd92e6dbad6df2dd50ad83caa49983a81b4)

@liach
> ```java
> var isZero = hashIsZero;
> if (isZero == 1) return 0;
> if (isZero == 2) {
>       int h = hash;
>       if (h != 0) return h;
> }
> return computeHash(); // and set hash, hashIsZero fields
> ```

Instead of `hashIsZero`, the field should be called `hashState` in that case.

And maybe use `-1` for the `hashCode() == 0` state and `+1` for the `hashCode() 
!= 0` state.

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

PR Comment: https://git.openjdk.org/jdk/pull/24625#issuecomment-2816567930

Reply via email to