2017-07-22 4 views
1

Diese Code-Kontrolle kommt aus:Reihenfolge der Null-Zeiger

http://hg.openjdk.java.net/code-tools/jcstress/file/tip/tests-custom/src/main/java/org/openjdk/jcstress/tests/volatiles/ReadAfterReadTest.java

public class ReadAfterReadTest { 
    private final Holder h1 = new Holder(); 
    private final Holder h2 = h1; 
    private static class Holder { 
     int a; 
     int trap; 
    } 
    @Actor 
    public void actor1() { 
     h1.a = 1; 
    } 
    @Actor 
    public void actor2(II_Result r) { 
     Holder h1 = this.h1; 
     Holder h2 = this.h2; 
     (*****) 
     // Spam null-pointer check folding: try to step on NPEs early. 
     // Doing this early frees compiler from moving h1.a and h2.a loads 
     // around, because it would not have to maintain exception order anymore. 
     (*****) 
     h1.trap = 0; 
     h2.trap = 0; 

     // Spam alias analysis: the code effectively reads the same field twice, 
     // but compiler does not know (h1 == h2) (i.e. does not check it, as 
     // this is not a profitable opt for real code), so it issues two independent 
     // loads. 
     r.r1 = h1.a; 
     r.r2 = h2.a; 
    } 
} 

ich nicht, was der Autor von den markierten mit (*****) Kommentar bedeutet das verstehen kann.

Antwort

0

Ich denke, er versucht, NullPointerException früh zu generieren. Das heißt: Wenn h1 oder h2 zu diesem Zeitpunkt null wäre, würde das Zuweisen von h1.trap = 0 eine NPE werfen.

Und die nächsten Zeilen erklären, warum dies hilft:

Doing this early frees compiler from moving h1.a and h2.a loads - ich denke, es ist für einige Optimierungen verwandt ist, dass der Compiler tut und JIT.

Die einfachste Möglichkeit besteht darin, eine Testklasse zu schreiben und den Bytecode für den Fall zu generieren, wenn Sie versuchen, auf einen übergebenen Variablenwert zuzugreifen, und wenn nicht und den Unterschied sehen.

Oder Sie können den Autor: Aleksey Shipilev (Schatten) @ aleksey-shipilev

Wenn Sie wirklich verstehen wollen, glaube ich Ihnen etwas über das lesen müssen:

https://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/ http://www.javaworld.com/article/2076060/build-ci-sdlc/compiler-optimizations.html

+0

@ aleksey-shipilev, können Sie das bitte kommentieren? – ACV

2

Java-Spezifikation erfordert, h1 und h2 Instanzen auf null zu überprüfen, bevor ihre Felder auch ohne explizite NPE-Prüfung abgefragt werden - diese Funktion wird auch als implizite Nullzeigerüberprüfung bezeichnet. Schauen wir uns Assembler-Code (durch JIT generiert):

0x00007f1fad2429f2: mov %rbx,0x18(%rsp) 
0x00007f1fad2429f7: mov (%rsp),%rbx 
0x00007f1fad2429fb: mov 0x10(%rsp),%rcx 
0x00007f1fad242a00: mov 0x28(%rsp),%r10 ;*aload 
0x00007f1fad242a05: mov 0x10(%rbx),%r11d ;*getfield h1 
0x00007f1fad242a09: mov 0xc(%r11),%edx  ;*getfield a 
               ; implicit exception: dispatches to 0x00007f1fad242b37 
0x00007f1fad242a0d: mov %r12d,0x10(%r11) ;*putfield trap 
0x00007f1fad242a11: mov 0x14(%rbx),%r9d ;*getfield h2 
0x00007f1fad242a15: mov %r12d,0x10(%r9) ;*putfield trap 
               ; implicit exception: dispatches to 0x00007f1fad242b49 
0x00007f1fad242a19: mov %r10,0x28(%rsp) 
0x00007f1fad242a1e: mov %rcx,0x10(%rsp) 

wo de-Referenzierung der Null-Zeiger wird SEGV Signal an den Prozess führen. VM verfügt über den SEGV-Handler, der das verarbeiten kann, und eine entsprechende NullPointerException (NPE) auslöst.

Dies kann als eine kleine Compiler-Barriere betrachtet werden, die einige Optimierungen verhindern kann, bei denen die Exception genau an die Stelle geworfen werden sollte, an der sie aufgetreten ist. Diese Überprüfung bietet Garantien, dass die weitere Ausführung des Codes keine NPE verursacht, daher kann der Compiler h1.a und h2.a Lasten verschieben, da er die Ausnahmebedingungen nicht mehr aufrechterhalten müsste.