RFR: 8186166: Generalize Atomic::cmpxchg with templates

David Holmes david.holmes at oracle.com
Mon Aug 14 05:08:23 UTC 2017


Hi Kim,

This is an initial partial review. I have to move onto other stuff today 
so will get back to this tomorrow.

On 14/08/2017 12:41 PM, Kim Barrett wrote:
> Please review this change to Atomic::cmpxchg, making it a function
> template with a per-platform underlying implementation.
> 
> This has been broken out from 8184334: "Generalizing Atomic with
> templates", as the originally proposed change there encountered
> various objections.  This change takes a somewhat different approach
> to the same problem.

I assume the intent is not to push this yet, so that Erik has a chance 
to weigh-in when he gets back from vacation? I would not want to see 
unnecessary churn here.

First for the record, and for those who followed the other review 
thread, I have been learning about template metaprogramming under Kim's 
guidance. I can see some uses for it, even though it can be extremely 
difficult to read and interpret. I'm not a Functional Programmer so I 
don't find the style of it particularly appealing, or "natural". But I'm 
no longer opposed to its use in moderation and with good taste - and 
with definite advantage to its use. :)

> One goal is to generalize the API and make it more type-safe,
> eliminating (nearly) all need for casts by callers.  Another is to
> allow more direct per-platform implementations, especially where there
> are appropriate compiler intrinsics available.

Sounds good.

> If all goes well and this change is accepted, it is intended that the
> remainder of Atomic, and later OrderAccess, will be changed in a
> similar manner as one or more followups.

Ok.

> This change to cmpxchg deprecates cmpxchg_ptr.  Followup changes will
> convert existing uses of cmpxchg_ptr and eventually remove it.
> Followup changes will also update uses of cmpxchg that can be
> simplified because of the generalized API.

Sounds good.

> The cmpxchg function calls private Atomic::CmpxchgImpl, to select
> among several cases, based on the argument types.  Each case performs
> some checking and possibly conversion to reach a standard form of the
> arguments (or fail and report a compile time error), which are then
> passed to private Atomic::PlatformCmpxchg.  The PlatformCmpxchg class
> is provided by each platform, and performs additional case analysis to
> generate the appropriate code for the platform.

Not sure how many levels of indirection we have here yet ...

> This change involves modifications to all of the existing platform
> implementations of cmpxchg.  I've updated all of the platforms, but
> only tested those supported by Oracle.  I'll need help from the
> various platform maintainers to check and test my changes.
> 
> Changes to files can be categorized as follows:
> 
> New metaprogramming utilities:
> integerTypes.hpp
> test_integerTypes.cpp
> isRegisteredEnum.hpp
> test_isRegisteredEnum.cpp
> 
> Change cmpxchg to a template:
> atomic.hpp
> 
> Oracle-supported platforms:
> atomic_bsd_x86.hpp - 64bit only
> atomic_linux_arm.hpp
> atomic_linux_x86.hpp
> atomic_solaris_sparc.hpp
> solaris_sparc.il
> atomic_solaris_x86.hpp
> atomic_windows_x86
> 
> Non-Oracle platform changes:
> atomic_aix_ppc.hpp
> atomic_bsd_x86.hpp - 32bit
> atomic_bsd_zero.hpp
> atomic_linux_aarch.hpp
> atomic_linux_ppc.hpp
> atomic_linux_s390.hpp
> atomic_linux_sparc.hpp
> atomic_linux_zero.hpp
> 
> Usage changes required by API change:
> os_bsd.cpp
> os_solaris.cpp
> aotCodeHeap.cpp
> aotCodeHeap.hpp
> psParallelCompact.hpp
> workgroup.cpp
> oopsHierarchy.hpp
> os.cpp
> 
> Example updates of cmpxchg_ptr to cmpxchg:
> oop.inline.hpp
> bitMap.cpp
> bitMap.inline.hpp
> 
> Some specific issues:
> 
> - For Solaris (both SPARC and x86), we were using helper functions
> defined in corresponding .il files.  Using the cmpxchg_using_stub
> helper didn't work; passing a "defined in .il" function as a template
> parameter didn't work, leading to linker errors.  The ideal solution
> is to use gcc-style inline assembly, which is now supported by Solaris
> Studio.  That change was made for SPARC.  However, making that change
> for x86 ran into related segfaults, so using the .il definition with
> direct conversions for now, until that problem can be resolved.

We already have an issue open for getting rid of the .il files:

https://bugs.openjdk.java.net/browse/JDK-8153076

The template usage probably adds fuel to the argument for doing so.

> - I've added the function template Atomic::condition_store_ptr, which
> is a cmpxchg for pointer types with a NULL compare_value.  That might
> not be the best name for it.

Definitely not the best name for it. :) replace_if_null seems to 
describe it more precisely.

> - The name IntegerTypes was retained from the original RFR for
> JDK-8184334.  However, that name no longer fits the provided
> functionality very well, and I think a new name is needed.  Something
> involving Bitwise, or ValueRepresentation perhaps?  I'm open to
> suggestions.

How about PrimitiveTypes?

> - Issues with casts/conversions provided by IntegerTypes.
> 
> * Conversions between integers and floating point values are
> supported.  It was suggested during the discussion of the RFR for
> JDK-8184334 that this was not needed, as there are no uses of
> atomic/ordered floating point values in Hotspot.  However, I'm told
> VarHandles may include atomic floating point values.

Yes they were added. However at the level of jdk.internal.misc.Unsafe 
all the FP operations are converted to int/long variants using eg 
Float.floatToRawIntBits etc.

But I'm not convinced we need to complicate things by supporting 
floating-point Atomic::cmpxchg in the VM's Atomic API. You can only do 
so by implementing the floatToRawIntBits etc functionality, and there 
are no native mappings for any "atomic" floating-point operation (ie the 
only way to do Atomic::inc on a floating=point value is to use cmpxchg.)

> * Conversions between integers and floating point values are presently
> implemented using the memcpy technique.  While this technique is
> correct, it is known to be quite poorly optimized by some compilers.
> It may be necessary to use the "union trick" for performance reasons,
> even though it is technically undefined behavior.  Hotspot already
> does this elsewhere (and we should merge some of the different
> conversion handling).

More argument for just avoiding this morass if we don't need to go there.

> * In the original RFR for JDK-8184334, conversions between different
> integral types of the same size (along with enums) were performed
> using
> 
>    reinterpret_cast<ToType&>(from_value)
> 
> This was based on discussion from several months ago, referring to
> C++03 3.10/15.  However, re-reading that section in response to
> discussion of the RFR for JDK-8184334, I now think that implementation
> is not supported in many cases needed here, and indeed invokes
> undefined behavior in those cases.  In particular, where 3.10/15 says
> 
>    "- a type that is the signed or unsigned type corresponding to the
>       dynamic type of the object,"
> 
> I interpret this to mean that if the dynamic type of an object is an
> integral type of a given rank, the value may be accessed using an
> lvalue of an integral type of the same rank and the opposite sign.
> (Using the same rank and sign is already permitted, since that's the
> same type.)  I don't think it allows access using an lvalue of an
> integral type with a different rank.  So, for example, a signed int
> value may be accessed via an unsigned int lvalue.  But access via a
> signed long lvalue is not permitted, even if int and long have the
> same size.
> 
> I don't think there is a good way to perform the integral and enum
> conversions we need, without invoking implementation-defined,
> unspecified, or undefined behavior.
> 
> ** The memcpy technique avoids such problems, but as noted above, is
> known to be quite poorly optimized by some compilers.
> 
> ** Using static_cast avoids any undefined behavior, but does have
> cases of implementation-defined or unspecified behavior.  (When
> casting an unsigned value to a signed type, the result may be
> implementation defined; 5.2.9/2 and 4.7/3.  C++11 <type_traits> plus
> the reinterpret_cast to reference seems to provide possibly multi-step
> conversion paths that avoid such qualifications on all of the steps.)
> (When casting an integral value to an enum type, the result may be
> unspecified; 5.2.9/7.  With C++11 <type_traits>, the problem doesn't
> arise so long as the starting value is appropriate, e.g. we're
> reversing an enum to integer conversion.)
> 
> ** Again here, we might consider the "union trick".
> 
> I haven't changed the implementation from the JDK-8184334 RFR, but I'm
> presently leaning toward the "union trick", despite previous strong
> resistance to it.  Right now it seems to me to be the best option in
> practice, despite being disallowed by the standard.  It's really too
> bad the memcpy technique is so poorly supported by some compilers.

I find that all rather dismaying.

> CR:
> https://bugs.openjdk.java.net/browse/JDK-8186166
> 
> Webrev:
> http://cr.openjdk.java.net/~kbarrett/8186166/hotspot.00/

Looking at the new metaprogramming files first:

src/share/vm/metaprogramming/integerTypes.hpp

With a bit of exertion I can read all this and am 90% confident I 
understand what they do.

src/share/vm/metaprogramming/isRegisteredEnum.hpp

My initial personal preference here is to see registered enum types 
added to this header file rather than as template specializations at the 
point of use. Is that reasonable/feasible, or are there reasons to 
spread this around?

test/native/metaprogramming/test_integerTypes.cpp
test/native/metaprogramming/test_isRegisteredEnum.cpp

Seems minimalist but ok.

Aside: I find it slightly limiting that because these templates involve 
compile-time checks, that we can't actually write negative tests. Seems 
to me that when writing the templates you had to write a test case that 
will fail, to verify the correctness of the template, but you can't 
check-in that testcase. Maybe we need a test harness that can handle 
'tests' that simply fail to compile ... ?

---

That's all for now.

Thanks,
David
-----


> Testing:
> Ad hoc Hotspot nightly test.
> 
> 


More information about the hotspot-dev mailing list