【问题标题】:Accessing values from Constant Pool Java Bytecode从常量池 Java 字节码访问值
【发布时间】:2016-01-06 15:09:20
【问题描述】:

我有以下代码:

    public static void f(){
        double i = 0.0;
        for(i = 0.0; i<100.0; i++){}   
    }

翻译成以下字节码:

public static void f();
Code:
   0: dconst_0
   1: dstore_0
   2: dconst_0
   3: dstore_0
   4: dload_0
   5: ldc2_w        #2                  // double 100.0d
   8: dcmpg
   9: ifge          19
  12: dload_0
  13: dconst_1
  14: dadd
  15: dstore_0
  16: goto          4
  19: return

我对包含评论 //double 100.0d 的行感到困惑

我有点理解ldc2_w 的作用。它从常量池中获取适当的常量。而且常量池中包含了解析Java代码后定义的常量列表,对吧?

但是#2 的目的是什么?怎么知道这里应该放什么数字?在一个在线教程中,我看到有人改用#4

这个操作数是什么意思?

【问题讨论】:

    标签: java constants bytecode operand


    【解决方案1】:

    但是#2 的目的是什么?怎么知道应该是什么号码 到这里?在一个在线教程中,我看到有人使用 #4 代替?

    通常你不会。如果您正在编写字节码汇编,您通常依赖汇编器为您填充常量池。

    例如,如果你写

    ldc2_w 100.0
    

    在 Jasmin 或 Krakatau 中,汇编器会自动为 100.0 创建一个常量池条目,然后填写相应的索引。可能是 2,可能是 4,可能是 50000。这取决于常量池中还有什么,但您通常不关心这些。

    Krakatau 汇编器还允许您手动指定常量池条目。所以如果你想确保你的替身在位置 2,你可以这样做

    .const [2] = Double 100.0
    ldc2_w [2]
    

    但是,几乎没有任何理由这样做。这仅在您关心类文件的确切二进制布局时才有用。

    至于为什么您会看到 #2,那是因为 Javap 就是这样。它用于快速检查字节码。如果你使用不同的工具,你会得到不同的结果。例如,Krakatau 反汇编程序只会打印出ldc2_w 100.0,除非您指定往返模式。

    【讨论】:

    • 作为旁注,我更喜欢bipush 100; i2d。这两条指令占用三个字节,就像单个 ldc2_w 指令一样,但不需要常量池条目(double 占用九个字节)。对于运行时性能,不太可能看到差异。
    【解决方案2】:

    #2 是常量池中该常量的索引,即常量池中的第二个条目。请注意,常量池还有其他条目,包括方法名称、字符串等。

    通常编译器会将 java 代码翻译成字节码指令,并同时添加任何所需的常量池条目。请参阅JVM Specification 中有关常量池数据结构的详细信息。还有像 ASM 这样的字节码操作框架和像 Jasmin 这样的字节码汇编器,它们完全从开发人员那里抽象出常量池的数量。

    【讨论】:

    • 但是在这种情况下只有一个常数,对吧? 100.0?那么索引不应该是#1吗?
    • 即,ldc2_w #1 会返回什么?
    • 更新了我的答案并进行了一些澄清,即如果条目 #1 不是长常量,则 ldc2_w #1 可能不是有效指令。
    • 假设你必须编写自己的字节码,比如说在考试的情况下,你得到了上面的 Java 代码。我怎么知道写 ldc2_w #2 ?我将如何查看常量池中的所有条目以得出 2?
    • @Greg - 通常你不会。汇编程序通常会为您处理这些问题。如果您手动创建整个类文件,您也将创建 const 池,因此知道什么在哪里。
    猜你喜欢
    • 2011-07-24
    • 1970-01-01
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 2013-10-03
    • 1970-01-01
    • 1970-01-01
    • 2014-06-08
    相关资源
    最近更新 更多