Unused java9 method

Suppose I have this code (it really doesn't matter, I think, but just in case here):

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 this is how I call it (using java-9):

  java -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+PrintIntrinsics AtomicJDK9 

I am trying to figure out which methods have been replaced by internal code. The first one that 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 really present in the output of the above call:

  @ 8 jdk.internal.misc.Unsafe::getAndAddInt (27 bytes) (intrinsic) 

But the whole conclusion looks strange (for me it 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 getAndAddInt present twice in the output?

In addition, if getAndAddInt is indeed replaced by an internal call, why it becomes necessary to replace all other internal methods with a call stack, they will no longer be used. I guess this is as simple as the stack of method calls moving from the bottom.

+8
java virtual-machine jvm java-9 jvm-arguments
source share
1 answer

To illustrate the compiler logic, I launched the JVM with the following arguments.

  -XX:-TieredCompilation -XX:CICompilerCount=1 -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining 

And what he 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 
  • Methods are built-in only for the compiler, but not for the interpreter.
  • Each method runs in the interpreter until it is considered hot .
  • AtomicInteger.getAndAdd is called not only from your code, but also from regular JDK code.
  • That is, AtomicInteger.getAndAdd reaches the call threshold a little earlier than your AtomicJDK9.atomicIncrement . Then getAndAdd sent to the compilation queue and where the first internal listing begins.
  • HotSpot JVM compiles methods in the background. While the method compiles, execution continues in the interpreter.
  • While AtomicInteger.getAndAdd interpreted, the Unsafe.getAndAddInt and Unsafe.weakCompareAndSwapIntVolatile also reach the call threshold and begin compiling. The following 3 embedded files are printed when compiling these Unsafe methods.
  • Finally, AtomicJDK9.atomicIncrement also reaches the threashold call and starts compiling. The last internal printout matches your method.
+7
source share

All Articles