Brought to you by EarthWeb
ITKnowledge Logo Login Graphic Click Here!
Click Here!
ITKnowledge
Find:
 
EXPERT SEARCH ----- nav

EarthWeb Direct

EarthWeb sites: other sites

Previous Table of Contents Next


The iinc instruction

The iinc instruction isn’t absolutely necessary. There aren’t 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, Sun’s 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, it’s now 2. Now we’re 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 they’re compared, and control jumps back to instruction 5. Once again, local variable 1 is incremented by 2. It’s 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 codes

You 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:


i2l int to long
i2f int to float
i2d int to double
l2i long to int
l2f long to float
l2d long to double
f2i float to int
f2l float to long
f2d float to double
d2i double to int
d2l double to long
d2f double to float
i2b int to byte
i2c int to char
i2s int to short

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

     }


Previous Table of Contents Next
HomeAbout UsSearchSubscribeAdvertising InfoContact UsFAQs
Use of this site is subject to certain Terms & Conditions.
Copyright (c) 1996-1999 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.