javaseiten.de   |   Version 0.6
 

4.13. JVM-Befehlssatz: Kurzbeschreibung J

 

 

Befehl Operandenstapel Opcode
jsr branchbyte1 branchbyte2 ... --> ..., address 0xa8

Führe eine Sprung zu einem Unterprogramm (Subroutine) aus.

Bezeichner Typ Beschreibung
branchbyte1 Vorzeichenloses Byte Zahlenwert zur Berechnung eines Sprung-Offsets.
branchbyte2 Vorzeichenloses Byte Zahlenwert zur Berechnung eines Sprung-Offsets.
address returnAddress Rücksprungadresse

Durch die Anweisung erfolgt ein Sprung an die Stelle im Programm, die sich aus einem Offset ergibt. Der vorzeichenbehaftete Offset berechnet sich zu: (branchbyte1 << 8) | branchbyte2. Die Anweisung jsr kann von einem Java-Compiler erzeugt werden, wenn eine finally-Klausel innerhalb des Java-Quelltextes enthalten ist (im Zusammenhang mit dem Befehl ret).

Beispiel:

Der weiter unten stehende Java-Quelltext enthält eine try-catch-finally-Anweisung. Der finally-Block wird im Beispiel immer aufgerufen, unabhängig davon ob eine Ausnahme ausgelöst wurde oder nicht (es wird z.B. eine NumberFormatException ausgelöst, wenn "0011" durch "0011x" im Quelltext ersetzt wird). Die zum Quellprogramm korrespondierenden JVM-Befehle wurden durch den Open-Source-Compiler Jikes linkextern.gif in der Version 1.22 erzeugt. Die Übersetzung der try-catch-finally-Anweisung in Bytecode wurde mit Hilfe von jsr und ret gelöst. Die Verwendung dieser beiden JVM-Befehle ist aber nicht zwingend erforderlich. Bei der Compilierung des Beispiels mit dem im JDK 6 enthaltenen Java-Compiler javac (Version 1.6.0) werden jsr und ret nicht innerhalb des erzeugten Bytecodes verwendet.

Auf der linken Seite der folgenden Übersicht befindet sich der Java-Quelltext und rechts daneben stehen die einzelnen JVM-Befehle, die durch den Java-Compiler Jikes erzeugt wurden. Im unteren Teil der Übersicht befindet sich die Exception-Tabelle, die zur Behandlung von möglicherweise erzeugten Ausnahmen nötig ist. Die Daten für diese Tabelle sind im Methodenbereich einer Klassendatei an entsprechender Stelle codiert und können ebenfalls mit Hilfe des Java-Disassemblers javap (Option -c) zur Anzeige gebracht werden. Im Anschluss an die Übersicht soll der Programmablauf anhand der erzeugten JVM-Befehle erläutert werden.

                                          (compiliert mit Jikes, Ver. 1.22)

int a = 0;                                 0: iconst_0
                                           1: istore_1
int i = 0;                                 2: iconst_0
                                           3: istore_2
try {                                      4: ldc #10; //String 0011
  i = Integer.parseInt("0011", 2);         6: iconst_2
                                           7: invokestatic #16; 
                                              //Method java/lang/Integer.
                                              parseInt:(Ljava/lang/String;I)I
                                          10: istore_2
                                          11: goto 35
} catch (NumberFormatException e) {       14: astore 5
  a++;                                    16: iinc 1,1
                                          19: goto 35
                                          22: astore_3
                                          23: jsr 28
                                          26: aload_3
                                          27: athrow
                                     
} finally {                               28: astore 4
   a--;                                   30: iinc 1,-1
}                                         33: ret 4

                                          35: jsr 28
                                          38: return

Exception-Tabelle:
from   to  target type
  4    11    14   Class java/lang/NumberFormatException
  4    26    22   any
 35    38    22   any

Der try-Block beginnt mit den beiden Anweisungen ldc #10 und 6: iconst_2, die benötigte Parameter für den Aufruf der statischen Methode parseInt auf den Operandenstapel legen. Der Methodenaufruf wird dann mit der Anweisung invokestatic #16 realisiert. Der weitere Programmfluss hängt nun davon ab, ob die aufgerufene Methode eine NumberFormatException auslöst oder ob der übergebene String (im Beispiel "0011") unter Vorgabe der Radix 2 in eine Integer-Zahl umgewandelt werden kann.

Im Beispiel erfolgt kein Auslösen der Exception und mit 11: goto 35 wird der aktuelle Block verlassen und an Stelle 35 im Bytecode gesprungen. Mit 35: jsr 28 wird zur Subroutine (finally-Block), die bei Bytecodestelle 28 beginnt, gesprungen. Der auf diesen Sprungbefehl folgende Opcode ist b1 für return und steht an Stelle 38. Der Wert dieser Stelle im Bytecode wird für den Rücksprung nach Beendigung der Subroutine benötigt und wird daher auf dem Operandenstapel zwischengespeichert (Typ returnAddress). Der erste Befehl der Subroutine astore 4 legt diesen obersten Wert des Stapels im Array der lokalen Variablen bei Index 4 ab. Anschließend wird der Wert der Variablen a um 1 vermindert. Mit ret 4 wird die Subroutine wieder verlassen, indem die Rücksprungadresse aus dem Array der lokalen Variablen bei Index 4 wieder ausgelesen und in das Register des Programmzählers (PC) geschrieben wird. Das Programm wird also an Bytecodestelle 38 mit der Anweisung return (letzter Befehl der main-Methode, aus der der Quelltext stammt) fortgesetzt.

Falls die Methode parseInt eine NumberFormatException auslöst, wird goto 35 an Bytecodestelle 11 nicht erreicht, sondern es wird an die Stelle 14 gesprungen (wie in der Exception-Tabelle angegeben: target 14). Bei dieser Stelle beginnt der catch-Block, der die erzeugte Ausnahme behandelt. Dieser Block wird schließlich mit 19: goto 35 verlassen, was zu einer Abarbeitung des finally-Blocks führt (siehe oben).

 

 

jsr_w branchbyte1 branchbyte2 branchbyte3 branchbyte4 ... --> ..., address 0xc9

Springe zu einem Unterprogramm (erweiterter Verzweigungsoffset).

Bezeichner Typ Beschreibung
branchbyte1 Vorzeichenloses Byte Zahlenwert zur Berechnung eines Sprung-Offsets.
branchbyte2 Vorzeichenloses Byte Zahlenwert zur Berechnung eines Sprung-Offsets.
branchbyte3 Vorzeichenloses Byte Zahlenwert zur Berechnung eines Sprung-Offsets.
branchbyte4 Vorzeichenloses Byte Zahlenwert zur Berechnung eines Sprung-Offsets.
address returnAddress Rücksprungadresse

Die Verwendung des Befehls jsr ermöglicht relative Sprünge von -32768 bzw. +32767, ausgehend von der Bytecodestelle des Opcodes des Sprungbefehls. Mit jsr_w steht ein erweiterter Verzweigungsoffset zur Verfügung, da bei diesem Befehl vier Verzweigungsbytes zur Verfügung stehen. Der vorzeichenbehaftete 32-Bit-Offset berechnet sich dabei wie folgt: (branchbyte1 << 24) | (branchbyte2 << 16) | (branchbyte3 << 8) | branchbyte4.

Beispiel: Siehe dazu jsr.

 

 

 

Diese Seite nutzt Google-Dienste - siehe dazu Datenschutz.

Copyright © 2006, 2007 Harald Roeder