2016-12-27 6 views
8

nehme ich diesen Code haben (es ist wirklich egal, wie ich glaube, aber nur für den Fall hier ist es):java9 intrinsische Methode unklar

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(); 
    } 
} 

Und hier ist, wie ich es bin Aufruf (mit java9):

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

Was ich herausfinden möchte, ist, welche Methoden durch intrinsischen Code ersetzt wurden. Die erste, die getroffen wird (innen 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; 
     } 

Und diese Methode in der Tat in der Ausgabe des obigen Aufrufs vorhanden ist:

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

Aber die gesamte Ausgabe ist seltsam (für mich, dass) ist:

@ 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) 

Warum die getAndAddInt in der Ausgabe zweimal vorhanden ist?

Auch wenn getAndAddInt in der Tat durch einen intrinsischen Aufruf ersetzt wird, warum ist es notwendig, alle anderen intrinsischen Methoden in den Aufrufstack zu ersetzen l sie werden nicht mehr verwendet werden. Ich nehme an, dass es so einfach ist, wie der Stapel von Methodenaufrufen von unten durchlaufen wird.

+1

vielleicht hinzufügen '+ PrintCompilation' (oder was auch immer das neue Unified Logging Äquivalent ist) und beleuchten den Kontext. – the8472

Antwort

7

Um die Compiler-Logik zu veranschaulichen, habe ich JVM mit den folgenden Argumenten ausgeführt.

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

Und das ist, was es druckt.

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 
  • Methoden sind intrinsics nur für Compiler, aber nicht für Dolmetscher.
  • Jede Methode wird im Interpreter gestartet, bis sie considered hot ist.
  • AtomicInteger.getAndAdd wird nicht nur aus Ihrem Code, sondern auch aus dem gängigen JDK-Code aufgerufen.
  • Das heißt, AtomicInteger.getAndAdd erreicht Aufruf Schwelle ein wenig früher als Ihre AtomicJDK9.atomicIncrement. Dann wird getAndAdd an die Kompilierungswarteschlange gesendet, und von dort kommt der erste intrinsische Ausdruck.
  • HotSpot JVM kompiliert Methoden im Hintergrund. Während eine Methode kompiliert wird, wird die Ausführung im Interpreter fortgesetzt.
  • Während AtomicInteger.getAndAdd interpretiert wird, erreichen die Methoden Unsafe.getAndAddInt und Unsafe.weakCompareAndSwapIntVolatile auch den Aufrufschwellenwert und beginnen mit der Kompilierung. Die nächsten 3 Intrinsics werden gedruckt, während diese Unsafe Methoden kompiliert werden.
  • Schließlich AtomicJDK9.atomicIncrement erreicht auch Aufruf Threashold und beginnt mit der Kompilierung. Der letzte intrinsische Ausdruck entspricht Ihrer Methode.