RFR: 8234563: Harmonize parameter order in Atomic

David Holmes david.holmes at oracle.com
Mon Nov 25 04:29:27 UTC 2019


Hi Stefan,

On 22/11/2019 9:14 pm, Stefan Karlsson wrote:
> On 2019-11-22 06:15, David Holmes wrote:
>> Hi Stefan,
>>
>> On 21/11/2019 9:26 pm, Stefan Karlsson wrote:
>>> Hi all,
>>>
>>> I'd like to propose a restructuring of the parameter order in Atomic.
>>
>> Okay - consistency is good, especially if it then aligns with external 
>> APIs. Thanks for doing this cleanup!
>>
>>> https://bugs.openjdk.java.net/browse/JDK-8234563
>>>
>>> These are some of the functions used to concurrently write memory 
>>> from HotSpot C++ code:
>>>
>>>   Atomic::store(value, destination);
>>>   OrderAccess::release_store(destination, value)
>>>   OrderAccess::release_store_fence(destination, value)
>>>   Atomic::add(value, destination);
>>>   Atomic::sub(value, destination);
>>>   Atomic::xchg(exchange_value, destination);
>>>   Atomic::cmpxchg(exchange_value, destination, compare_value);
>>>
>>> With the proposed JDK-8234562 change, this would look like:
>>>
>>>   Atomic::store(value, destination);
>>>   Atomic::release_store(destination, value)
>>>   Atomic::release_store_fence(destination, value)
>>>   Atomic::add(value, destination);
>>>   Atomic::sub(value, destination);
>>>   Atomic::xchg(exchange_value, destination);
>>>   Atomic::cmpxchg(exchange_value, destination, compare_value);
>>>
>>> I'd like to propose that we move the destination parameter over to 
>>> the left, and the new value to the right. This would look like this:
>>>
>>>   Atomic::store(destination, value);
>>>   Atomic::release_store(destination, value)
>>>   Atomic::release_store_fence(destination, value)
>>>   Atomic::add(destination, value);
>>>   Atomic::sub(destination, value);
>>>   Atomic::xchg(destination, exchange_value);
>>>   Atomic::cmpxchg(destination, compare_value, exchange_value);
>>
>> I was expecting
>>
>> Atomic::cmpxchg(destination, exchange_value, compare_value);
>>
>> as that would seem more consistent so that we always have:
>> - arg 1 => destination
>> - arg 2 => new (or delta) value
>>
>> but I guess this is consistent with external cmpxchg APIs :(
>>
>>> This would bring the Atomic API more in-line with the order for a 
>>> normal store:
>>>
>>> *destination = value;
>>>
>>> I've split this up into separate patches, each dealing with a 
>>> separate operation:
>>>
>>> Atomic::store:
>>>   https://cr.openjdk.java.net/~stefank/8234563/webrev.01.01.store/
>>
>> Ok.
>>
>>> Atomic::add:
>>>   https://cr.openjdk.java.net/~stefank/8234563/webrev.01.02.add/
>>
>> src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il
>>
>> You updated the comments to show the parameters have changed order but 
>> the assembly code is unchanged - won't it need modification too? Or is 
>> it that the true call site for this still uses the original order ??
>>
> 
> Right. I've changed the order for the C++ functions, but left inline 
> assembly that assumes a given parameter order. I didn't want to change 
> that with this patch. Here's where the arguments are swapped:
> 
> // Not using add_using_helper; see comment for cmpxchg.
> template<>
> template<typename D, typename I>
> inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I 
> add_value,
>                                                 atomic_memory_order 
> order) const {
>    STATIC_ASSERT(4 == sizeof(I));
>    STATIC_ASSERT(4 == sizeof(D));
>    return PrimitiveConversions::cast<D>(
>      _Atomic_add(PrimitiveConversions::cast<int32_t>(add_value),
>                  reinterpret_cast<int32_t volatile*>(dest)));
> }

Thanks for pointing that out.

> So, the comment refers to the high-level Atomic::add function, not the 
> _Atomic_add implementation. I agree that it's confusing, and thought 
> about that, but I don't have a good suggestion how to change these 
> comments. If you have a good suggestion on what to changes this to, I 
> can update all these comments.

How about:

   // Support for jint Atomic::add(volatile jint* dest, jint add_value)
   // called via _Atomic_add(jint add_value, volatile jint* dest)

or perhaps

   // Implementation of jint _Atomic_add(jint add_value, volatile jint* 
dest)
   // used by Atomic::add(volatile jint* dest, jint add_value)

>> -- 
>>
>> I was a bit confused about the changes involving 
>> Atomic::add_using_helper:
>>
>> +template<typename Type, typename Fn, typename D, typename I>
>> +inline D Atomic::add_using_helper(Fn fn, D volatile* dest, I 
>> add_value) {
>>     return PrimitiveConversions::cast<D>(
>>       fn(PrimitiveConversions::cast<Type>(add_value),
>>          reinterpret_cast<Type volatile*>(dest)));
>>
>> because you switched the Atomic API parameter order, but the 
>> underlying function being called still has the parameters passed in 
>> the old order. I'm not sure whether this is the right level to stop 
>> the change or whether it should have been pushed all the way down to 
>> e.g. os::atomic_add_func ?
> 
> If I wanted to push this further down I would have to start to change 
> assembly code that relied on a specific order. That's why I chose to 
> stop here.

Understood.

> See:
> add_func_t*          os::atomic_add_func          = 
> os::atomic_add_bootstrap;
> 
> ---
> 
> int32_t os::atomic_add_bootstrap(int32_t add_value, volatile int32_t* 
> dest) {
>    // try to use the stub:
>    add_func_t* func = CAST_TO_FN_PTR(add_func_t*, 
> StubRoutines::atomic_add_entry());
>    if (func != NULL) {
>      os::atomic_add_func = func;
>      return (*func)(add_value, dest);
>    }
>    assert(Threads::number_of_threads() == 0, "for bootstrap only");
>    return (*dest) += add_value;
> }
> 
> ---
> 
> StubRoutines::_atomic_add_entry           = generate_atomic_add();
> 
> ---
>    address generate_atomic_add() {
>      StubCodeMark mark(this, "StubRoutines", "atomic_add");
>      address start = __ pc();
>      __ movl(rax, c_rarg0);
>      __ lock();
>      __ xaddl(Address(c_rarg1, 0), c_rarg0);
>      __ addl(rax, c_rarg0);
>      __ ret(0);
>      return start;
>    }
> 
> I'd prefer to leave that exercise to someone else.

Fair enough :)

Thanks,
David
-----

> 
>>
>> Otherwise seems okay.
>>
>>> Atomic::sub:
>>>   https://cr.openjdk.java.net/~stefank/8234563/webrev.01.03.sub/
>>
>> Ok.
>>
>>> Atomic::xchg:
>>>   https://cr.openjdk.java.net/~stefank/8234563/webrev.01.04.xchg/
>>
>> src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il
>>
>> same issue with the assembly as per Atomic::add.
>>
>> ---
>>
>> Same issue/query with xchg_using_helper as add_using_helper.
>>
>>> Atomic::cmpxchg:
>>>   https://cr.openjdk.java.net/~stefank/8234563/webrev.01.05.cmpxchg/
>>
>> src/hotspot/os_cpu/bsd_x86/bsd_x86_32.s
>> src/hotspot/os_cpu/linux_x86/linux_x86_32.s
>> src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il
>>
>> Again queries about the actual assembly code.
> 
> Thanks for reviewing this,
> StefanK
> 
>>
>> Thanks,
>> David
>> -----
>>
>>> All sub-patches combined:
>>>   https://cr.openjdk.java.net/~stefank/8234563/webrev.01.all/
>>>
>>> The patches applies on-top of the patch for JDK-8234562:
>>>   https://cr.openjdk.java.net/~stefank/8234562/webrev.01/
>>>
>>> I've tested this patch with tier1-7. I've also built fastdebug on the 
>>> following configs: aarch64, arm32, ppc64le, s390x, shenandoah, zero, 
>>> minimal, just to minimize any disruptions. However, this is a moving 
>>> target and latest rebase of this has only been run on tier1.
>>>
>>> Thanks,
>>> StefanK


More information about the hotspot-dev mailing list