![]() |
|||
![]() ![]() |
![]() |
|
![]() |
The iinc instructionThe iinc instruction isnt absolutely necessary. There arent any Java source files that cannot be compiled without it. However, it does allow loops to run much more quickly. The byte immediately after the iinc instruction in the code array is an unsigned index into the local variable array. The byte after that is a signed byte by which the local variable will be incremented. The iinc instruction is most commonly used to compile the ++, --, += and -= operators, especially in loops. The iinc instruction is the only one that operates directly on a value in the local variable array without moving the value onto the stack first. For example, consider this for loop: public void loop() { for (int i = 0; i < 20; i += 2) { } } With no optimization, Suns javac 1.0.2 compiler compiles this to public void loop() { 0 iconst_0 1 istore_1 2 goto 3 0 4 6 5 iinc 6 1 7 2 8 iload_1 9 bipush 10 20 11 if_icmplt 12 -1 13 -6 14 return } The zeroth instruction, iconst_0, pushes the int 0 onto the operand stack. The second instruction, istore_1, moves the int onto the top of the stack into local variable 1. Therefore, local variable 1 is now 0. The second instruction, goto, reads the next two bytes as a signed short telling how many bytes to jump over. Here, the value of the short is 6, so the goto jumps to instruction 8, iload_1. This instruction pushes the int in local variable 1 onto the stack. Next, instruction 9, bipush, pushes the value 20 onto the stack. Instruction 11 pops the top two values from the stack and checks to see whether the second value popped (the int that was one down in the stack) is less than the second value popped (the int that was on top of the stack). If it is, then the next two bytes are read as the signed short address of the instruction to which control should jump. In this case, control jumps back six bytes, that is, to instruction 11 - 6, which is instruction 5, iinc. The first byte after iinc is 1, and the second byte is 2, so 2 is added to local variable 1. Because local variable 1 was 0, its now 2. Now were back at instruction 7. Again, local variable 1 is pushed onto the stack, and the int constant 20 is pushed onto the stack. Once again theyre compared, and control jumps back to instruction 5. Once again, local variable 1 is incremented by 2. Its now 4. This continues until local variable 1 reaches the value 20. At that point, the comparison fails, and control moves to statement 14, return. The alternative way to compile this code, without the iinc instruction, takes many more instructions. You have to push extra values onto the stack, add them there, and then store the result back in local variable 1, like this: public void loop() { 0 iconst_0 1 istore_1 2 goto 6 5 iload_1 6 iconst_2 7 iadd 8 istore_1 9 iload_1 10 bipush 20 12 if_icmplt 13 -1 14 -7 15 return } With the iinc instruction, the for loop is one byte and three instructions shorter than it would be otherwise. Conversion codesYou may have noticed that all the instructions discussed so far operate only on values of the same type. For example, there are instructions to add two ints, to add two floats, to add two longs, and to add two doubles. However, there is no instruction that adds an int to a double, a float to a double, a float to a long, or any other combination of primitive data types. At the level of the virtual machine, only values of the same type may be operated on or compared. Before a statement like float f = 7.5 + 6; can be compiled, the int value 6 must be promoted to a float. There are 14 conversion instructions. They all look like i2l or f2d. The first letter is the type from which you convert. The last letter is the type to which you convert. Thus, i2l converts an int to a long, and f2d converts a float to a double. All conversions take place as specified in the Java Language Specification and in Chapter 2 of this book. Each of these instructions pops the appropriate number of words from the stack (one for an int or a float and two for a long or a double) and pushes the converted value back onto the stack. The instructions are as follows:
For example, the method here is compiled to the byte codes that follow: public double convert() { int i = 6; double d = i; return d; } Note in particular instruction 6, where the int value 6 on top of the stack is promoted to the double value 6.0 before being stored in the local variable array. The other conversion instructions are used in exactly the same way. public double convert() { 0 bipush 6 2 istore_1 3 iload_1 4 i2d 5 dstore_2 6 dload_2 7 dreturn }
|
![]() |
|