RFR: 8186838: Generalize Atomic::inc/dec with templates

Andrew Haley aph at redhat.com
Fri Sep 1 13:41:01 UTC 2017


On 31/08/17 13:45, Erik Österlund wrote:
> Hi everyone,
> 
> Bug ID:
> https://bugs.openjdk.java.net/browse/JDK-8186838
> 
> Webrev:
> http://cr.openjdk.java.net/~eosterlund/8186838/webrev.00/
> 
> The time has come for the next step in generalizing Atomic with 
> templates. Today I will focus on Atomic::inc/dec.
> 
> I have tried to mimic the new Kim style that seems to have been 
> universally accepted. Like Atomic::add and Atomic::cmpxchg, the 
> structure looks like this:
> 
> Layer 1) Atomic::inc/dec calls an IncImpl()/DecImpl() function object 
> that performs some basic type checks.
> Layer 2) IncImpl/DecImpl calls PlatformInc/PlatformDec that can define 
> the operation arbitrarily for a given platform. The default 
> implementation if not specialized for a platform is to call Atomic::add. 
> So only platforms that want to do something different than that as an 
> optimization have to provide a specialization.
> Layer 3) Platforms that decide to specialize PlatformInc/PlatformDec to 
> be more optimized may inherit from a helper class 
> IncUsingConstant/DecUsingConstant. This helper helps performing the 
> necessary computation what the increment/decrement should be after 
> pointer scaling using CRTP. The PlatformInc/PlatformDec operation then 
> only needs to define an inc/dec member function, and will then get all 
> the context information necessary to generate a more optimized 
> implementation. Easy peasy.

I wanted to say something nice, but I honestly can't.  I am dismayed.

I hoped that inc/dec would turn out to be much simpler than the
cmpxchg functions: I think they should, because they don't have to
deal with the complexity of potentially three different types.
Instead we have, again, a large and complex patch.

Even on AArch64, which should be the simplest case because Atomic::inc
can be defined as

template <typename T1>
inc(T1 *dest) {
  return __sync_add_and_fetch(dest, 1);
}

or something similar, we have

Atomic::inc<int>
Atomic::IncImpl<int, void>::operator()
Atomic::PlatformInc<4ul, IntegralConstant<int, 1> >::operator()
Atomic::add<int, int>
Atomic::AddImpl<int, int, void>::operator()
Atomic::AddAndFetch<Atomic::PlatformAdd<4ul> >::operator()<int, int>
Atomic::PlatformAdd<4ul>::add_and_fetch<int, int>
__sync_add_and_fetch

I quite understand that it isn't so easy on some systems, and they
need a generic form that explodes into four different calls, one for
each size of integer.  I completely accept that it will be more
complex for everything else.  But is it necessary to have so much code
for something so simple?  This is a 1400 line patch.  Granted, much of
it is simply moving stuff around, but despite the potential of
template code to simplify the implementation we have a more complex
solution than we had before.

I ask you, is this the simplest solution that you believe is possible?

-- 
Andrew Haley
Java Platform Lead Engineer
Red Hat UK Ltd. <https://www.redhat.com>
EAC8 43EB D3EF DB98 CC77 2FAD A5CD 6035 332F A671


More information about the hotspot-dev mailing list