I compiled the following method:
public static final boolean equalTo(final int x, final int y) {
return x == y;
}
And with javap
could see that the following bytecode was produced for it:
public static final boolean equalTo(int, int);
descriptor: (II)Z
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
Code:
stack=2, locals=2, args_size=2
0: iload_0
1: iload_1
2: if_icmpne 9
5: iconst_1
6: goto 10
9: iconst_0
10: ireturn
LineNumberTable:
line 72: 0
StackMapTable: number_of_entries = 2
frame_type = 9 /* same */
frame_type = 64 /* same_locals_1_stack_item */
stack = [ int ]
I wrote ASM that would create the same bytecode, and also created another version that behaved the same by changing the goto 10
to an ireturn
. It's negligible, but this also reduces the size of the StackMapTable
since it eliminates a jump.
I know "it's only bytecode" and not indicative of what the machine will do, but why does the compiler emit goto 10
when it could simply emit ireturn
?
Frontend compilers generate code using simple patterns, and they rely on optimization passes to clean things up. At the point that the x == y
expression is generated, the compiler doesn't "know" that the very next thing is a return statement. It could potentially check this, but that extra step can be handled just as easily with some sort of peephole optimizer.
The benefit of a peephole optimizer is that it can perform cascading optimizations, that is, the result of one optimization can feed into the next one. The code that generated the x == y
expression doesn't really have any way of performing anything more than one optimization step without adding more complexity.
The java compiler used to have an optimization feature, but this was ditched in favor of HotSpot, which can perform even more powerful optimizations. Performing optimizations in the java compiler would slow it down and not really improve things all that much.