Why copy a link to a field to a local file before using it in a loop?

What is the advantage of this line of OpenJDK number 1455 .

Code snippet:

private final char value[]; // ... public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; // <--- this line for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; } 

Note that although the link to the private final char value[] copied to the local val for access inside the loop, its .length field is still accessible via value , not val .

I suspect that β€œ performance ” is the answer (for example, it’s faster to read from the local than from the field), but I would appreciate an accurate and easy to read answer, maybe even some evidence of the benefits.

+6
source share
1 answer

I took a look at the bytecode, as @user noted, this is probably an optimization to avoid getting getfield in a loop. But they got messed up and still refer to the value variable in the loop state ... so this actually makes the bytecode longer and slower.

 public int h1() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; } public int h2() { int h = hash; if (h == 0 && value.length > 0) { for (int i = 0; i < value.length; i++) { h = 31 * h + value[i]; } hash = h; } return h; } 

We see that both methods produce almost identical bytecode, however, our β€œoptimized” implementation actually ends up using two more calls.

Notice how the for loop test (lines 39-45 in h1 and lines 37-43 in h2) calls getfield to call the length of the array.

Bytecode:

 public int h1(); Code: 0: aload_0 1: getfield #17 // Field hash:I 4: istore_1 5: iload_1 6: ifne 53 9: aload_0 10: getfield #15 // Field value:[C 13: arraylength 14: ifle 53 17: aload_0 18: getfield #15 // Field value:[C 21: astore_2 22: iconst_0 23: istore_3 24: goto 39 27: bipush 31 29: iload_1 30: imul 31: aload_2 32: iload_3 33: caload 34: iadd 35: istore_1 36: iinc 3, 1 39: iload_3 40: aload_0 41: getfield #15 // Field value:[C 44: arraylength 45: if_icmplt 27 48: aload_0 49: iload_1 50: putfield #17 // Field hash:I 53: iload_1 54: ireturn public int h2(); Code: 0: aload_0 1: getfield #17 // Field hash:I 4: istore_1 5: iload_1 6: ifne 51 9: aload_0 10: getfield #15 // Field value:[C 13: arraylength 14: ifle 51 17: iconst_0 18: istore_2 19: goto 37 22: bipush 31 24: iload_1 25: imul 26: aload_0 27: getfield #15 // Field value:[C 30: iload_2 31: caload 32: iadd 33: istore_1 34: iinc 2, 1 37: iload_2 38: aload_0 39: getfield #15 // Field value:[C 42: arraylength 43: if_icmplt 22 46: aload_0 47: iload_1 48: putfield #17 // Field hash:I 51: iload_1 52: ireturn 

If they changed the loop condition to also use the local field,

 ... for (int i = 0; i < val.length; i++) { ... 

Then the bytecode actually gets shorter and loses, possibly, a slower getfield call in the loop,

  public int h1(); Code: 0: aload_0 1: getfield #17 // Field hash:I 4: istore_1 5: iload_1 6: ifne 50 9: aload_0 10: getfield #15 // Field value:[C 13: arraylength 14: ifle 50 17: aload_0 18: getfield #15 // Field value:[C 21: astore_2 22: iconst_0 23: istore_3 24: goto 39 27: bipush 31 29: iload_1 30: imul 31: aload_2 32: iload_3 33: caload 34: iadd 35: istore_1 36: iinc 3, 1 39: iload_3 40: aload_2 41: arraylength 42: if_icmplt 27 45: aload_0 46: iload_1 47: putfield #17 // Field hash:I 50: iload_1 51: ireturn 

Performing a silent simple cycle test over a method several million times on my jdk 1.7.0_79, it consistently shows that the original method funny takes about 5 times longer to run , then either not optimized or properly optimized methods. The last 2 are not have differences in performance.

So, I assume that preserving the local field was an attempt to optimize the bytecode methods, probably before jit could optimize it themselves, but they messed it up and actually made the method much worse ...

This code is actually fixed in Java 9 per, https://bugs.openjdk.java.net/browse/JDK-8058643

+3
source

All Articles