Suppose I have this code (it really does not matter I think, but just in case here it is):
public class AtomicJDK9 {
     static AtomicInteger ai = new AtomicInteger(0);
     public static void main(String[] args) {
        int sum = 0;
        for (int i = 0; i < 30_000; ++i) {
           sum += atomicIncrement();
        }
        System.out.println(sum);
     }
     public static int atomicIncrement() {
         ai.getAndAdd(12);
         return ai.get();
     }
}
And here is how I am invoking it (using java-9):
 java -XX:+UnlockDiagnosticVMOptions 
      -XX:-TieredCompilation  
      -XX:+PrintIntrinsics  
      AtomicJDK9
What I am trying to find out is what methods were replaced by intrinsic code. The first one that is hit (inside Unsafe):
      @HotSpotIntrinsicCandidate
      public final int getAndAddInt(Object o, long offset, int delta) {
         int v;
         do {
            v = getIntVolatile(o, offset);
         } while (!weakCompareAndSwapIntVolatile(o, offset, v, v + delta));
         return v;
      }
And this method is indeed present in the output of the above invocation:
 @ 8   jdk.internal.misc.Unsafe::getAndAddInt (27 bytes)   (intrinsic)
But, the entire output is weird (for me that is):
 @ 8   jdk.internal.misc.Unsafe::getAndAddInt (27 bytes)   (intrinsic)
 @ 3   jdk.internal.misc.Unsafe::getIntVolatile (0 bytes)   (intrinsic)
 @ 18  jdk.internal.misc.Unsafe::weakCompareAndSwapIntVolatile (11 bytes)   (intrinsic)
 @ 7   jdk.internal.misc.Unsafe::compareAndSwapInt (0 bytes)   (intrinsic)
 @ 8   jdk.internal.misc.Unsafe::getAndAddInt (27 bytes)   (intrinsic)
Why is the getAndAddInt present twice in the output?
Also if getAndAddInt is indeed replaced by an intrinsic call, why is there a need to replace all other intrinsic methods down the call stackl they will not be used anymore. I do assume it's as simple as the stack of method calls is traversed from the bottom.
In order to illustrate the compiler logic I ran JVM with the following arguments.
    -XX:-TieredCompilation -XX:CICompilerCount=1
    -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining 
And that's what it prints.
337   29   java.util.concurrent.atomic.AtomicInteger::getAndAdd (12 bytes)
              @ 8   jdk.internal.misc.Unsafe::getAndAddInt (27 bytes)   (intrinsic)
337   30   jdk.internal.misc.Unsafe::getAndAddInt (27 bytes)
              @ 3   jdk.internal.misc.Unsafe::getIntVolatile (0 bytes)   (intrinsic)
              @ 18   jdk.internal.misc.Unsafe::weakCompareAndSwapIntVolatile (11 bytes)   (intrinsic)
338   32   jdk.internal.misc.Unsafe::weakCompareAndSwapIntVolatile (11 bytes)
              @ 7   jdk.internal.misc.Unsafe::compareAndSwapInt (0 bytes)   (intrinsic)
339   33   AtomicJDK9::atomicIncrement (16 bytes)
              @ 5   java.util.concurrent.atomic.AtomicInteger::getAndAdd (12 bytes)   inline (hot)
                @ 8   jdk.internal.misc.Unsafe::getAndAddInt (27 bytes)   (intrinsic)
              @ 12   java.util.concurrent.atomic.AtomicInteger::get (5 bytes)   accessor
AtomicInteger.getAndAdd is called not only from your code, but from common JDK code, too.AtomicInteger.getAndAdd reaches invocation threshold a little bit earlier than your AtomicJDK9.atomicIncrement. Then getAndAdd is submitted to compilation queue, and that's where the first intrinsic printout comes from.AtomicInteger.getAndAdd is interpreted, Unsafe.getAndAddInt and Unsafe.weakCompareAndSwapIntVolatile methods also reach invocation threshold and begin compilation. The next 3 intrinsics are printed while compiling these Unsafe methods.AtomicJDK9.atomicIncrement also reaches invocation threashold and begin compilation. The last intrinsic printout corresponds to your method.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With