java JVM字节码表示法,注释语法。调用动态

标签 java jvm jvm-bytecode javap

问题:第 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 项调用虚拟函数。调用的方法是println()来自类(class)java/io/PrintStream , 它的输入来自类 Ljava/lang/String ,其返回值为Void。

至于第 14 行,#0 持有对 BootstrapMethod 的引用,并返回一个 Object,其类为 CallSite。对?
然后:
  • #20 指的是什么?
  • 什么评论#0:makeConcatWithConstants:(I)Ljava/lang/String;方法?

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

    最佳答案

    简短版本: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" .

    现在,引导方法的工作是返回一个 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 方法,但对于我们的小示例来说,这已经足够了)。

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

    默认策略是 MethodHandle 链接。

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

    关于java JVM字节码表示法,注释语法。调用动态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61485900/

    相关文章:

    java - 没有明确答案 : Which Java Map is the cheapest?

    java - 是否可以通过指定 Gcflags来修复 OutOfMemory 错误?

    java - Java 平台独立性将如何运作?

    java - 使用 "invokedynamic"- 幕后发生了什么?

    java - IF_ICMPNE 是什么意思?

    java - Oracle EBS .ClassNotFoundException : oracle. apps.fnd.formsClient.FormsLauncher.class 错误

    java - JNA通过java找不到dll文件中指定的程序

    java - WebView 显示空白页面而不是加载链接

    java - 使用 sa-jli 将 ClassDump 禁用到正在运行的 JVM 进程

    jvm - JVM 操作数栈必须是确定性的吗?