On Fri, 21 Mar 2025 17:26:08 GMT, Quan Anh Mai <qa...@openjdk.org> wrote:
>>> Hi again Per!
>>> 
>>> Here are some brief notes from our face-to-face chat at JavaOne.
>>> 
>>> Debuggers want/need a "hook" for tentative evaluation of stables. It is an 
>>> error for a debugger to trigger stable value decisions. This applies mainly 
>>> to stable lists because of `toString`.
>>> 
>>> Just how "mutable" is a stable list? How "eager to decide"? Which methods 
>>> (if any) are tentative: `toString` / `equals` / `hashCode` ? Currently in 
>>> the PR, all are decisive. This might be a case of the “wrong default”.
>> 
>> IMHO if we claim that what the API constructs is a `List`, it would be weird 
>> for these methods to behave any different.
>> 
>>> 
>>> Maybe refactor composites to expose systematically "tenative" access API:
>>> 
>>>     * Less universal: SV.list(My::compute) => List
>>> 
>>>     * More universal; SV.stableList(My::compute) => List<StableSupplier>
>>> 
>>> 
>>> BTW, it’s easy to understand a stable-list as a list of stables. But let’s 
>>> be sure to leave room for a more compact data structure. A compact 
>>> stable-list is a list of stable views into a backing array. The backing 
>>> array looks like `@Stable private T[] resolvedValues`. Not `private final 
>>> List<StableValue<T>> stableValues`.
>> 
>> I don't disagree -- there's two list factories, one that returns a plain 
>> List<T> and one that returns a List<SV<T>>. The important thing is we leave 
>> room for both (which means naming is important). But I think we're ok for 
>> this round even if we don't provide the second factory given that it can be 
>> "emulated" (although in a not as compact fashion -- but is that a problem?)
>> 
>> In other words, I'd like to base some of these decisions more on concrete 
>> use cases. We had plenty use cases for List<T> -- very few for List<SV<T>>. 
>> Maybe some real world use will show that, indeed a List<SV<T>> factory 
>> belongs here -- in which case, sure let's add one.
>> 
>> tl;dr; let's get the naming right now -- but add the API later.
>> 
>>> 
>>> For the record: I think this is sufficient for correctness: Use 
>>> `getAcquire` (resp. `releaseSet`) for all stable reads (resp. writes. Do 
>>> the `releaseSet` inside a mutex that serializes computation. Add a 
>>> re-entrancy check in the mutex and throw on vicious cycles.
>>> 
>>> I do NOT think `volatile` is necessary; it has too many fences. It is a 
>>> safe default for a naked variable. But the stable variables are 
>>> encapsulated, and do not need aggressive fences.
>> 
>> As I said, `volatile` might not be necessary but it does make the 
>> implementation easier to validate (I think)...
>
>> In all these cases there is a fast path: e.g. when we know we have already 
>> warned for enable native access, or for Unsafe. In the SV API, the fast path 
>> is when we know that the SV is set already. In my experience, the volatile 
>> access in this fast path costs nothing: whenever I looked at the generated 
>> C2 code for hot paths of FFM code using enable-native-access, it seems that, 
>> once the stable field is set, the fact that it is volatile no longer 
>> matters. There's no barrier generated by C2 -- access is as fast as plain 
>> access.
> 
> An acquire load is allowed to be reordered with a preceding volatile store 
> and I believe this is the only case where it makes a difference. E.g::
> 
>     x = load_acquire(p);
>     store_volatile(p, v);
>     y = load_acquire(p);
> 
> can be transformed into:
> 
>     x = load_acquire(p);
>     y = x;
>     store_volatile(p, v);
> 
> Furthermore, on Aarch64, volatile load is implemented with `ldar` while 
> acquire load can be implemented with `ldr`.

@merykitty 
> Furthermore, on Aarch64, volatile load is implemented with ldar while acquire 
> load can be implemented with ldr.

I'm not sure exactly what you mean here but I don't think that sounds right?

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

PR Comment: https://git.openjdk.org/jdk/pull/23972#issuecomment-2744379545

Reply via email to