Sponsored Link •
|
Advertisement
|
The Hop Around applet, included below, demonstrates a Java virtual machine executing a sequence of bytecodes. This applet accompanies Chapter 18, "Finally Clauses," of Inside the Java 2 Virtual Machine.
The bytecode sequence in the simulation was generated by the javac
compiler for the hopAround()
method of the class shown below:
// On CD-ROM in file opcodes/ex1/Clown.java class Clown { static int hopAround() { int i = 0; while (true) { try { try { i = 1; } finally { // The first finally clause i = 2; } i = 3; // This return never completes, because of // the continue in the second finally clause return i; } finally { // The second finally clause if (i == 3) { // This continue overrides the return statement continue; } } } } }
The bytecodes generated by javac
for the hopAround()
method are shown here:
0 iconst_0 // Push constant 0 1 istore_0 // Pop into local var 0: int i = 0; // Both try blocks start here (see exception table, below): 2 iconst_1 // Push constant 1 3 istore_0 // Pop into local var 0: i = 1; 4 jsr 18 // Jump to mini-subroutine at offset 18 (the // first finally clause) 7 goto 24 // Jump to offset 24 (to just below first // finally clause) // Catch clause for the first finally clause: 10 astore 4 // Pop the reference to thrown exception, store // in local variable 4 12 jsr 18 // Jump to mini-subroutine at offset 18 (the // first finally clause) 15 aload 4 // Push the reference (to thrown exception) // from local variable 4 17 athrow // Rethrow the same exception // The first finally clause: 18 astore 5 // Store the return address in local variable 5 20 iconst_2 // Push constant 2 21 istore_0 // Pop into local var 0: i = 2; 22 ret 5 // Jump to return address stored in local variable 5 // Bytecodes for the code just after the first finally clause: 24 iconst_3 // Push constant 3 25 istore_0 // Pop into local var 0: int i = 3; // Bytecodes for the return statment: 26 iload_0 // Push the int from local // variable 0 (i, which is 3) 27 istore_1 // Pop and store the int into local // variable 1 (the return value, i) 28 jsr 39 // Jump to mini-subroutine at offset 39 (the // second finally clause) 31 iload_1 // Push the int from local variable 1 (the // return value) 32 ireturn // Return the int on the top of the stack // Catch clause for the second finally clause: 33 astore_2 // Pop the reference to thrown exception, store // in local variable 2 34 jsr 39 // Jump to mini-subroutine at offset 39 (the // second finally clause) 37 aload_2 // Push the reference (to thrown exception) // from local variable 2 38 athrow // Rethrow the same exception // The second finally clause: 39 astore_3 // Store the return address in local variable 3 40 iload_0 // Push the int from local variable 0 (i) 41 iconst_3 // Push constant 3 42 if_icmpeq 47 // If the top two ints on the stack are equal, jump // to offset 47: if (i == 3) { 45 ret 3 // Jump to return address stored in local variable 3 47 goto 2 // Jump to offset 2 (the top of the while // block): continue; Exception table: from to target type 2 4 10 any 2 31 31 any
The hopAround()
method returns from the first finally
clause by executing past the closing curly brace, but returns from the second finally
clause by executing a continue
statement. The first finally
clause, therefore, exits via its ret
instruction. But because the second finally
clause exits via a continue
, its ret
instruction is never executed. The continue
statement causes the Java virtual machine to jump to the top of the while
loop again. This results in an endless loop, even though it is a return
statement that originally causes the second finally
clause to be executed in the first place. The continue statement in the finally
clause supersedes the return
statement, so the method never returns.
Note that the bytecodes that implement the return
statement store a copy of the return value into local variable one before jumping to the miniature subroutine that represents the second finally
clause. Then, after the miniature subroutine returns (in this case it never does, because the continue is always executed), the return value is retrieved from local variable one and returned.
This highlights the way the Java virtual machine returns values when finally
clauses are also executed. Rather than returning the value of i
after the finally
clause is executed, the Java virtual machine will return the value that i
had just before the finally
clause was executed. This means that even if the finally
clause changes the value of i
, the method will still return the value that i
had when the return
statement was first reached, before the finally
clause was invoked. If you wanted the finally
clause to be able to change the return value of the method, you would have to put an actual return
statement with the new return value into the finally
clause itself.
To drive the Hop Around simulation, use the Step, Reset, Run, and Stop buttons. Each time you press the Step button, the simulator will execute the instruction pointed to by the pc register. If you press the Run button, the simulation will continue with no further coaxing on your part until you press the Stop button. To start the simulation over, press the Reset button. For each step of the simulation, a panel at the bottom of the applet contains an explanation of what the next instruction will do. Happy clicking.
Click here to view a page of links to the source code of the Hop Around applet.
Sponsored Links
|