Another kind of special branch is the jsr, for jump subroutine. It's like a goto that remembers where it came from. Or you can think of it as a method invocation that doesn't create a new stack frame. For example, state1: jsr get_next_character ; Go to the subroutine that leaves ; the next char on top of the stack lookupswitch ; Jump to the next state 65: state1 ; Go to state 1 if the value is 65 66: state2 ; Go to state 2 if the value is 66 default: state3 ; Otherwise, go to state 3 get_next_character: ; At this point, there's a returnAddress on top of the stack astore_3 ; Store it in variable 3 ;; Do code to get the next character, ;; and leave it on top of the stack ret 3 ; Return to the location in variable 3 The jsr is used to take code that would otherwise have to be replicated in several places and put it in a single place. It's not quite as powerful as putting it into a separate method, since there's no explicit facilities for passing arguments. It is less expensive to use, however, since the machine doesn't have to create a whole new stack frame. When jsr is executed, it branches to the location specified by the label, and it leaves a special kind of value on the stack called a returnAddress to represent the return address. It's your responsibility to remember this value by storing it in a local variable. The value is a kind of reference, so you use the aload and astore instructions to store its value. However, you can't call methods on it, store it in a field, or use it as an argument to a method. As with the other branches, the label must be inside the body of the same method as the jsr instruction. At the end of a subroutine, you can return to the instruction after the jsr with a ret. A ret is different from a return, which is used to return from an invocation. The argument to ret is a number that represents a local variable. That variable should contain the return address that was on the stack at the beginning of the subroutine. |