How should the offset for the JVM transition command be 32768?

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++; // ... (10921 times - too much code to post here!) y++; y++; } System.out.println(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?

+7
java c casting jvm specifications
source share
2 answers

The if_icmpge argument is an offset, but javap shows the transition target as an absolute position. That is, javap should show getstatic at 32768: and not 32770: (i.e. 2 + 32768).

+3
source share

I wrote simple scala code to generate code to dig further. For all kinds of transition commands, an offset is signed to support reverse and forward transitions.

If the offset is less than 0x7FFF, I see the goto statement, and if the offset is greater than 0x7FFF, I see the goto_w statement.

Thus, the method in Java is limited to 65535 bytes since LineNumberTable, LocalVariableTable, exception_table ... and is limited to 65535 bytes. The JVM uses goto / goto_w commands to jump to a signed 16/32 offset as needed.

0
source share

All Articles