Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do Java decompilers discern a for-loop from a while-loop?

Consider these two methods:

public static void forLoop(int start, int limit) {
    for (int i = start; i < limit; i++) {

    }
}

public static void whileLoop(int start, int limit) {
    int i = start;
    while (i < limit) {
        i++;
    }
}

When compiled, they produce the bytecode (this is the verbose output of javap):

  public static void forLoop(int, int);
    descriptor: (II)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=2
         0: iload_0
         1: istore_2
         2: iload_2
         3: iload_1
         4: if_icmpge     13
         7: iinc          2, 1
        10: goto          2
        13: return
      LineNumberTable:
        line 6: 0
        line 9: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            2      11     2     i   I
            0      14     0 start   I
            0      14     1 limit   I

  public static void whileLoop(int, int);
    descriptor: (II)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=2
         0: iload_0
         1: istore_2
         2: iload_2
         3: iload_1
         4: if_icmpge     13
         7: iinc          2, 1
        10: goto          2
        13: return
      LineNumberTable:
        line 12: 0
        line 13: 2
        line 14: 7
        line 16: 13
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      14     0 start   I
            0      14     1 limit   I
            2      12     2     i   I

As you can see, the code section for both of these methods is exactly the same. However, when I decompile this class using JD, it correctly produces:

public static void forLoop(int start, int limit) {
  for (int i = start; i < limit; i++) {}
}

public static void whileLoop(int start, int limit)
{
  int i = start;
  while (i < limit) {
    i++;
  }
}

How was it able to do this? The bytecode of these methods is exactly the same! Despite the fact that the LineNumberTable and LocalVariableTable attributes were different for each method, I am reluctant to believe that is the reason since those are not required attributes for the Code attribute of a method to contain (per section 4.7 of The Java Language Specification, Java SE 8 Edition).

like image 432
Martin Tuskevicius Avatar asked Aug 23 '16 22:08

Martin Tuskevicius


1 Answers

The line numbers and local variable scope.

for loop:

 LineNumberTable:
    line 6: 0
    line 9: 13
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        2      11     2     i   I
        0      14     0 start   I
        0      14     1 limit   I

while loop:

LineNumberTable:
        line 12: 0
        line 13: 2
        line 14: 7
        line 16: 13
  LocalVariableTable:
    Start  Length  Slot  Name   Signature
        0      14     0 start   I
        0      14     1 limit   I
        2      12     2     i   I

The for loop has fewer distinct lines of code - which makes sense because it wraps up the initialization and increment in one line.

like image 165
Jonathon Reinhart Avatar answered Oct 02 '22 12:10

Jonathon Reinhart