When writing an answer to the question about JVM byte code offsets, I noticed something in the behavior of javac and the resulting class files, which I cannot explain:
When compiling this class
class FarJump { public static void main(String args[]) { call(0, 1); } public static void call(int x, int y) { if (x < y) { y++; y++;
then the received bytecode will contain the following if_icmpge command:
public static void call(int, int); Code: 0: iload_0 1: iload_1 2: if_icmpge 32768 5: iinc 1, 1 8: iinc 1, 1 ...
According to the documentation of the transition instructions, the offset (which in this case is 32768) is calculated as follows:
If the comparison is successful, unsigned branches 1 and branches 2 are used to build the signed 16-bit offset, where the offset is calculated as (branchbyte1 <8) | branchbyte2.
Thus, the offset is considered a signed 16-bit value. However, the maximum value that a signed 16-bit value can have is 32767, not 32768.
The resulting class file still seems valid and can execute as usual.
I looked at the bytecode checking in OpenJDK , and it seems (to me) that this is only true because of the parentheses shackled:
int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2];
It will output the first byte to a signed char . Then it will apply the shift and add the second byte. I would expect it to be
int jump = (((signed char)(code[offset+1]) << 8)) + code[offset+2];
or maybe even
int jump = (signed char)((code[offset+1]) << 8) + code[offset+2]);
but I'm not familiar with type advertisements and the possible caveats associated with the compiler for switching between signed and unsigned types, so I'm not sure if there is a deeper meaning for this actor ...
So, does the jump offset match 32768 specifications? And does OpenJDK jump calculation code make sense in this regard?