【问题标题】:java JVM bytecode notation, comment grammar. InvokeDynamicjava JVM字节码表示法,注释语法。调用动态
【发布时间】:2020-08-12 14:28:18
【问题描述】:

问题:第 14 行是什么意思?

使用javap -v -c反汇编如下代码:

 public class test {
     static int i = 2;
     public static void main(String[] args) {
         test x = new test();
         System.out.println("text + String: " + i);
     } 
 }

在主函数中我们得到以下内容:

14: invokedynamic #20,  0             // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
19: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
...
BootstrapMethods:
  0: #38 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
    Method arguments:
      #44 text + String: \u0001

因此,例如,第 19 行表示从运行时常量池中的 #24 项调用虚拟函数。调用的方法是来自类java/io/PrintStream的println(),它的输入来自类Ljava/lang/String,它的返回值是Void。

至于第 14 行,#0 持有对 BootstrapMethod 的引用,并返回一个其类为 CallSite 的对象,对吗? 然后:

  1. #20 指向什么?
  2. 评论#0:makeConcatWithConstants:(I)Ljava/lang/String;是什么意思?

另外,我在哪里可以找到有关 Javap 反汇编代码语法的更多信息?或者什么是正确的关键字? Oracle 关于the JVM instruction set 的文档似乎没有清楚地描述评论的含义。

【问题讨论】:

    标签: java jvm jvm-bytecode javap


    【解决方案1】:

    简短版本:Java 从 Java 9 开始使用 invokedynamic 连接字符串。

    让我们稍微分解一下:

    Invokedynamic 有两个步骤:

    • 第一次调用指令时,会调用引导方法。当它返回时,调用站点将链接到引导方法的结果。
    • 后续调用将直接调用目标MethodHandle。

    CallSite 只是 MethodHandle 的持有者。根据所使用的CallSite 子类,该站点可能稍后会重新链接。

    如果我们查看指令,我们会在末尾看到以下内容:

    #0:makeConcatWithConstants:(I)Ljava/lang/String;
    

    第一部分(#0)表示:引导方法#0。
    第二部分是名称 - 传递给引导方法,可能会或可能不会在其中使用。
    第三部分是生成的目标的方法类型。在我们的例子中:一个接受 int 并返回 java.lang.String 的方法。

    如果我们现在看一下引导方法#0,我们会看到一个方法参考,这里是StringConcatFactory.makeConcatWithConstants(...)。 我们还看到还有一个额外的参数:字符串"text + String: \u0001"。

    bootstrap 方法的工作现在是返回一个 MethodHandle(在 CallSite 内),在这种情况下,它执行此字符串连接。但是它如何进行字符串连接(StringBuilder、String.format、字节码旋转、链接 MethodHandles...)对于实际的类并不重要。它只想连接字符串。


    让我们尝试手动模拟这种行为。 bootstrap 方法毕竟是普通的 Java 方法:

    public static void main(String[] args) throws Throwable {
        CallSite cs = StringConcatFactory.makeConcatWithConstants(MethodHandles.lookup(),
                "makeConcatWithConstants", MethodType.methodType(String.class, int.class),
                "text + String: \u0001");
    
        int x = 2;
        String result = (String) cs.dynamicInvoker().invokeExact(x);
        System.out.println(result);
    
        x = 3;
        result = (String) cs.dynamicInvoker().invokeExact(x);
        System.out.println(result);
    }
    

    (VM 做了更多的事情,比如它会记住结果并且不会再次调用 bootstrap 方法,但对于我们的小示例来说这已经足够了)。


    此时,我们可以深入了解引导方法的工作原理。
    事实证明:您可以配置 VM 以使用不同的策略。
    它使用它在 java.base 中的特权位置来访问 java.lang.String 的包私有构造函数,该构造函数不复制数组 - 如果之后不修改内容,这是安全的。

    默认策略是 MethodHandle 链式。

    好消息是:如果有人在某个时候编写了更好的策略,您的程序将从中受益 - 无需重新编译。

    【讨论】:

    • 您好,非常感谢您提供非常详细的回答及更多信息!还有一个问题:您能否进一步解释一下“它使用它在 java.base 中的特权位置来访问包私有构造函数...”部分,或者我应该使用什么关键字来搜索有关此引用的更多信息?
    • 啊,是的。 java.lang.String has a few package private constructors。不要使用它们——但是如果你实现了不可变类型,那么设计是很好的。
    【解决方案2】:

    参考the JVM specification:

    首先,无符号indexbyte1和indexbyte2用于构造一个索引到当前类的运行时常量池中(§2.6),...索引处的运行时常量池入口必须是符号引用到动态计算的调用站点(第 5.1 节)。

    方便的是,javap 确实已经查找了常量池并解码了信息;结果就是在行中的指令后面像注释一样打印出来的内容

    14: invokedynamic #20,  0             // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
    

    数字#0 是您已经发布的BootstrapMethods 属性的索引。方法名称的含义取决于该引导方法。还有type descriptor(I)Ljava/lang/String;,所以这个特定的调用会消耗int并产生String。

    运行时会发生什么取决于引用的引导方法。此调用引用了 static 方法 StringConcatFactory.makeConcatWithConstants(...),其中一部分是使用 Java 9 编译字符串连接。

    documentation of that method 告诉我们invokedynamic 指令中使用的方法名是无关紧要的,BootstrapMethod 属性的静态参数,即text + String: \u0001 决定了字符串格式。 \u0001 是“普通参数”的占位符,即 int 参数。

    【讨论】:

    • 您好,非常感谢您提供清晰准确的参考答案。我会接受约翰内斯的回答,因为他的回答稍早一些,并提供了一些额外的扩展,但这个回答也很棒。也衷心感谢您!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多