Die Tatsache, dass jedes Throwable eine Instanz von java.lang.Throwable
ist, wird an verschiedenen Stellen des Java-Byte-Codes/JVM impliziert. Auch wenn Handler für jede gedacht waren, etwas möglicherweise außerhalb der Throwable
Typ Hierarchie darzustellen, scheitert die Idee wie die heutigen Klassendateien ein StackMapTable
für Methoden enthalten Exception-Handler haben müssen und dass StackMapTable
zum jeder throwable als Instanz beziehen von java.lang.Throwable
1.
Auch mit dem alten Typ Inferenzabschnitts Verifizierer, eine Prozedur, die wieder wirft ein throwable implizit die Behauptung enthält, daß jeder throwable eine Instanz von java.lang.Throwable
ist wie das einzige Objekt ist athrow
erlaubt ist, zu werfen.
http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.athrow
The objectref müssen reference
Typ sein und auf ein Objekt verweisen, das eine Instanz der Klasse ist Throwable
oder eine Unterklasse von Throwable
.
Kurze Antwort: Nein, es ist unmöglich, eine Situation zu haben, wo etwas anderes als eine Instanz von java.lang.Throwable
(oder einer Unterklasse) geworfen werden kann oder gefangen.
Ich habe versucht, ein minimales Beispiel für eine Try-with-Resource-Anweisung zu erstellen, um die Ausgabe von javac
zu analysieren. Das Ergebnis zeigt deutlich, dass die Struktur ein Artefakt davon ist, wie javac
intern arbeitet, aber nicht beabsichtigt sein kann.
Das Beispiel sieht wie folgt aus:
public static void tryWithAuto() throws Exception {
try (AutoCloseable c=dummy()) {
bar();
}
}
private static AutoCloseable dummy() {
return null;
}
private static void bar() {
}
(I mit jdk1.8.0_20
kompiliert)
ich die Ausnahmebehandlungstabelle zu Beginn des resultierenden Byte-Code eingeben, damit es einfacher ist, an den Ort, während zu beziehen in der Befehlsfolge suchen:
Exception table:
from to target type
17 23 26 Class java/lang/Throwable
6 9 44 Class java/lang/Throwable
6 9 49 any
58 64 67 Class java/lang/Throwable
44 50 49 any
nun mit den Anweisungen:
Der Beginn ist einfach, zwei lokale Variablen werden verwendet, man den AutoCloseable
(Index 0), das andere für die mögliche throwable (Index 1, initialisiert mit null
) zu halten. dummy()
und bar()
aufgerufen wird, dann wird die AutoCloseable
für null
geprüft, um zu sehen, ob es geschlossen werden muss.
0: invokestatic #2 // Method dummy:()Ljava/lang/AutoCloseable;
3: astore_0
4: aconst_null
5: astore_1
6: invokestatic #3 // Method bar:()V
9: aload_0
10: ifnull 86
Wir bekommen hier, wenn die AutoCloseable
nicht null
und das erste seltsame Sache passiert ist, die throwable, die auf jeden Fall ist null
geprüft wird für null
13: aload_1
14: ifnull 35
Der folgende Code wird das AutoCloseable
, bewacht von schließen der erste Ausnahmebehandler aus der obigen Tabelle, der addSuppressed
aufruft. Da zu diesem Zeitpunkt, 1 Variable # ist null
ist dieser dead-Code:
17: aload_0
18: invokeinterface #4, 1 // InterfaceMethod java/lang/AutoCloseable.close:()V
23: goto 86
26: astore_2
27: aload_1
28: aload_2
29: invokevirtual #6 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
32: goto 86
Beachten Sie, dass die letzte Anweisung des toten Code ist goto 86
, eine Verzweigung zu einem return
so, wenn der Code oben nicht tot Code war sowieso wir konnten, starten Sie fragen sich, warum addSuppressed
auf einem Throwable
Aufruf plagen, die gleich danach ignoriert.
folgt nun den Code, wenn die Variable # 1 ausgeführt wird, ist null
(lesen, immer). Es ruft einfach close
und verzweigt in die return
Anweisung, keine Ausnahme abfangen, so dass eine durch close()
geworfene Ausnahme propagiert den Anrufer:
35: aload_0
36: invokeinterface #4, 1 // InterfaceMethod java/lang/AutoCloseable.close:()V
41: goto 86
Jetzt treten wir in den zweiten Exception-Handler, für den Körper der try
Aussage, erklärt zu fangen Throwable
, lesen Sie alle Ausnahmen. Es speichert die Throwable
wie erwartet in die Variable # 1, speichert sie aber auch in der veralteten Variablen # 2. Dann wirft es erneut die Throwable
.
44: astore_2
45: aload_2
46: astore_1
47: aload_2
48: athrow
Der folgende Code ist das Ziel von zwei Ausnahmeroutinen. Erstens ist es das Ziel der überflüssige jede Exception-Handler, der den gleichen Bereich wie die Throwable
Handler deckt damit, wie Sie vermutet, wird diese Prozedur nichts tun. Ferner ist es das Ziel des vierten Ausnahmebehandlers, der alles abfängt und den obigen Ausnahmebehandler abdeckt, so dass wir die erneut geworfene Ausnahme des Befehls 48 direkt eine Anweisung später abfangen.Um die Dinge noch lustiger zu machen, deckt der Ausnahmebehandler mehr als den obigen Handler ab; auf Platz # 50, exklusive endet, umfasst es auch die erste Anweisung von selbst:
49: astore_3
Das erste, was ist es, eine dritte Variable einzuführen, um die gleiche throwable zu halten. Jetzt wird die AutoCloseable
auf null
überprüft.
50: aload_0
51: ifnull 84
Nun ist die throwable der Variable # 1 ist für null
geprüft. Es kann nur null
sein, wenn das hypothetische Throwable kein Throwable
ist. Aber beachten Sie, dass der gesamte Code würde in diesem Fall durch den Gutachter abgelehnt werden, da die StackMapTable
alle Variablen und Operanden erklärt Einträge Stapel der jede throwable Halte Zuordnung kompatibel sein zu java.lang.Throwable
54: aload_1
55: ifnull 78
58: aload_0
59: invokeinterface #4, 1 // InterfaceMethod java/lang/AutoCloseable.close:()V
64: goto 84
Last but not least haben wir der Ausnahmebehandler, der die Ausnahme behandelt, die durch Schließen ausgelöst wird, wenn eine ausstehende Ausnahme vorhanden ist, die addSuppressed
aufruft und die primäre Ausnahme erneut auslöst. Es führt eine andere lokale Variablen ein, die anzeigt, dass javac
indeed never uses swap
sogar wo angemessen ist.
67: astore 4
69: aload_1
70: aload 4
72: invokevirtual #6 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
75: goto 84
So sind die beiden folgenden Anweisungen sind nur dann, wenn Fang aufgerufen jede etwas anderes als java.lang.Throwable
bedeuten könnte, das nicht der Fall ist. Der Code-Pfad verbindet sich bei # 84 mit dem regulären Fall.
78: aload_0
79: invokeinterface #4, 1 // InterfaceMethod java/lang/AutoCloseable.close:()V
84: aload_3
85: athrow
86: return
So lautet das Fazit ist, dass die zusätzlichen Exception-Handler für jeden nur für toten Code von vier Befehlen verantwortlich sind, # 54, # 55, # 78 und 79 #, während es noch mehr toter Code ist für andere Gründe (# 17 - # 32), plus ein merkwürdiger "Wurf-und-Fang" (# 44 - # 48) Code, der auch ein Artefakt der Idee sein könnte, irgendein anders als Throwable
zu behandeln. Außerdem hat ein Ausnahmebehandler einen falschen Bereich, der sich auf "Strange exception table entry produced by Sun's javac" als suggested in the comments bezieht.
Als Randbemerkung, produziert von Eclipse einfachen Code nimmt nur 60 Bytes statt 87 für die Befehlsfolge, nur die beiden erwarteten Ausnahmebehandler und mit drei lokalen Variablen anstelle von fünf Jahren. Und innerhalb dieses kompakteren Codes behandelt es den möglichen Fall, dass die Ausnahme, die vom Körper geworfen wird, dieselbe sein kann wie die eine durch close
geschüttete Ausnahme, wobei addSuppressed
nicht aufgerufen werden muss. Der javac
generierte Code kümmert sich nicht darum.
0: aconst_null
1: astore_0
2: aconst_null
3: astore_1
4: invokestatic #18 // Method dummy:()Ljava/lang/AutoCloseable;
7: astore_2
8: invokestatic #22 // Method bar:()V
11: aload_2
12: ifnull 59
15: aload_2
16: invokeinterface #25, 1 // InterfaceMethod java/lang/AutoCloseable.close:()V
21: goto 59
24: astore_0
25: aload_2
26: ifnull 35
29: aload_2
30: invokeinterface #25, 1 // InterfaceMethod java/lang/AutoCloseable.close:()V
35: aload_0
36: athrow
37: astore_1
38: aload_0
39: ifnonnull 47
42: aload_1
43: astore_0
44: goto 57
47: aload_0
48: aload_1
49: if_acmpeq 57
52: aload_0
53: aload_1
54: invokevirtual #30 // Method java/lang/Throwable.addSuppressed:(Ljava/lang/Throwable;)V
57: aload_0
58: athrow
59: return
Exception table:
from to target type
8 11 24 any
4 37 37 any
Bitte senden Sie das vollständige Bytecode. –
https://dl.dropboxusercontent.com/u/26793257/example.txt –
und hier ist der Jimple-Code (der von Ruß erzeugt wird): https://dl.dropboxusercontent.com/u/26793257/Beispiel. jimple.txt Ich habe zwei Kommentare eingefügt, um auf die relevanten Zeilen hinzuweisen. –