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.
And that's what it prints.
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 yourAtomicJDK9.atomicIncrement
. ThengetAndAdd
is submitted to compilation queue, and that's where the first intrinsic printout comes from.AtomicInteger.getAndAdd
is interpreted,Unsafe.getAndAddInt
andUnsafe.weakCompareAndSwapIntVolatile
methods also reach invocation threshold and begin compilation. The next 3 intrinsics are printed while compiling theseUnsafe
methods.AtomicJDK9.atomicIncrement
also reaches invocation threashold and begin compilation. The last intrinsic printout corresponds to your method.