JVM跳转指令的偏移量如何为32768?

Mar*_*o13 7 c java jvm casting specifications

在写一个关于JVM字节码偏移的问题答案时,我注意到javac的行为以及我无法解释的结果类文件:

编译这样的类时

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

然后生成的字节代码将包含以下if_icmpge指令:

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
       ...
Run Code Online (Sandbox Code Playgroud)

根据跳转指令的文档,偏移量(在这种情况下为32768)计算如下:

如果比较成功,则使用无符号branchbyte1branchbyte2构造带符号的16位偏移量,其中偏移量计算为(branchbyte1 << 8)| branchbyte2.

因此,偏移被称为带符号的 16位值.但是,有符号 16位值可以容纳的最大值是32767,而不是32768.

生成的类文件似乎仍然有效,并且可以正常执行.

我看一下OpenJDK中的字节码检查,似乎(对我而言)这只是由于括号错位而有效:

int jump = (((signed char)(code[offset+1])) << 8) + code[offset+2];
Run Code Online (Sandbox Code Playgroud)

它会将第一个字节转换为signed char.然后它将应用移位,并添加第二个字节.我原以为是

int jump = (((signed char)(code[offset+1]) << 8)) + code[offset+2];
Run Code Online (Sandbox Code Playgroud)

或者甚至是

int jump = (signed char)((code[offset+1]) << 8) + code[offset+2]);
Run Code Online (Sandbox Code Playgroud)

但是我不熟悉类型促销和可能的特定于编译器的转移有符号和无符号类型的警告,所以我不确定这个转换背后是否有更深层的含义......

那么32768的跳跃偏移是否符合规范?在这方面,OpenJDK中的跳转计算代码是否有意义?

Bre*_*ail 5

to 的参数if_icmpge是偏移量,但 javap 将跳转目标显示为绝对位置。也就是说,javap 应该显示getstaticat32768:而不是32770:(即 2 + 32768)。