这些Java字节偏移量如何计算? [英] How are these Java byte offsets calculated?

查看:685
本文介绍了这些Java字节偏移量如何计算?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下Java代码:

I have the following Java code:

public int sign(int a) {
  if(a<0) return -1;
  else if (a>0) return 1;
  else return 0;
}

在编译时会生成以下字节码:

which when compiled generated the following bytecode:

public int sign(int);
  Code:
     0: iload_1
     1: ifge          6
     4: iconst_m1
     5: ireturn
     6: iload_1
     7: ifle          12
    10: iconst_1
    11: ireturn
    12: iconst_0
    13: ireturn

我想知道字节偏移量计数(第一列)的计算方式,尤其是当所有其他指令均为单字节指令时,为什么ifgeifle指令的字节计数为3个字节?

I want to know how the byte offset count (the first column) is calculated, in particular, why is the byte count for the ifge and ifle instructions 3 bytes when all the other instructions are single byte instructions?

推荐答案

正如注释中已经指出的:ifgeifle指令还有一个额外的偏移量.

As already pointed out in the comment: The ifge and ifle instructions have an additional offset.

Java虚拟ifgeifle 的机器指令集规范在此处包含相关提示:

The Java Virtual Machine Instruction Set specification for ifge and ifle contains the relevant hint here:

格式

if<cond>
branchbyte1
branchbyte2

这表示该指令还有两个附加字节,即分支字节".这些字节由一个单独的short值组成,以确定 offset -即满足条件时指令指针应跳转"多远.

This indicates that there are two additional bytes associated with this instruction, namely the "branch bytes". These bytes are composed to a single short value to determine the offset - namely, how far the instruction pointer should "jump" when the condition is satisfied.

这些评论让我感到好奇:offset被定义为一个 signed 16位值,将跳转限制在+/- 32k的范围内.这并不涵盖可能方法的全部范围,该方法根据类文件中的code_length最多可包含65535个字节.

The comments made me curious: The offset is defined to be a signed 16 bit value, limiting the jumps to the range of +/- 32k. This does not cover the whole range of a possible method, which may contain up to 65535 bytes according to the code_length in the class file.

所以我创建了一个测试类,看看会发生什么.此类看起来像这样:

So I created a test class, to see what happens. This class looks like this:

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) ...

            y++;
            y++;
        }
        System.out.println(y);
    }

}

y++行中的每一行都将转换为由3个字节组成的iinc指令.所以最终的字节码是

Each of the y++ lines will be translated into a iinc instruction, consisting of 3 bytes. So the resulting byte code is

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

       ...(10921 times) ...

    32762: iinc          1, 1
    32765: iinc          1, 1
    32768: getstatic     #3             // Field java/lang/System.out:Ljava/io/PrintStream;
    32771: iload_1
    32772: invokevirtual #4             // Method java/io/PrintStream.println:(I)V
    32775: return

可以看到它仍然使用if_icmpge指令,其偏移量为32768(这是绝对偏移量. relative 偏移量是32766.另请参见此问题)

One can see that it still uses an if_icmpge instruction, with an offset of 32768 ( It is an absolute offset. The relative offset is 32766. Also see this question)

通过在原始代码中再添加一个y++,编译后的代码突然变为

By adding a single more y++ in the original code, the compiled code suddenly changes to

public static void call(int, int);
    Code:
       0: iload_0
       1: iload_1
       2: if_icmplt     10
       5: goto_w        32781
      10: iinc          1, 1
      13: iinc          1, 1
      ....
    32770: iinc          1, 1
    32773: iinc          1, 1
    32776: goto_w        32781
    32781: getstatic     #3             // Field java/lang/System.out:Ljava/io/PrintStream;
    32784: iload_1
    32785: invokevirtual #4             // Method java/io/PrintStream.println:(I)V
    32788: return

因此它将条件从if_icmpge转换为if_icmplt,并使用

So it reverses the condition from if_icmpge to if_icmplt, and handles the far jump with a goto_w instruction, that contains four branch bytes and can thus cover (more than) a full method range.

这篇关于这些Java字节偏移量如何计算?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆