首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >java字节码符号,注释语法。InvokeDynamic

java字节码符号,注释语法。InvokeDynamic
EN

Stack Overflow用户
提问于 2020-04-28 17:09:20
回答 2查看 272关注 0票数 4

问:第14行是什么意思?

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

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

在主要功能中,我们得到以下内容:

代码语言:javascript
复制
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项中的invokevirtual。被调用的方法是来自类println()java/io/PrintStream,它的输入来自类Ljava/lang/String,其返回值是无效的。

至于第14行,#0保存对BootstrapMethod的引用,并返回一个类为CallSite正确的对象?然后:

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

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-04-28 21:05:04

简短的版本: Java使用invokedynamic连接自Java 9以来的字符串。

让我们把这一点分解一下:

Invokedynamic有两个步骤:

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

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

如果我们看一下这条指令,我们会在最后看到以下内容:

代码语言:javascript
复制
#0:makeConcatWithConstants:(I)Ljava/lang/String;

第一部分(#0)的意思是:引导方法#0。

第二部分是名称--它传递给引导方法,可以在那里使用,也可以不使用。

第三部分是结果目标的方法类型。在本例中:获取int并返回java.lang.String的方法。

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

引导方法现在的任务是返回一个MethodHandle (在CallSite中),在这种情况下,这个字符串连接。但是它是如何进行字符串连接的(StringBuilder,String.format,字节码旋转,链接MethodHandles.)对于实际的类来说并不重要。它只想把String连接起来。

让我们试着用手来模仿这种行为。毕竟,引导方法是一个普通的Java方法:

代码语言:javascript
复制
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做了更多的事情,比如它会记住结果,不会再次调用引导方法,但是对于我们的小例子来说,这已经足够好了)。

在这一点上,我们可以查看一下引导方法是如何工作的。

结果是:您可以将VM配置为使用不同的策略。

它使用java.base中的特权位置来访问不复制数组的java.lang.String的包私有构造函数--如果之后不修改内容,这是安全的。

默认策略是MethodHandle链接。

好消息是:如果有人在某个时候写了一个更好的策略,你的程序就会从中受益--不需要重新编译。

票数 5
EN

Stack Overflow用户

发布于 2020-04-28 21:07:26

请参阅JVM规范

首先,未签名的indexbyte1和indexbyte2用于为当前类的运行时常量池构造索引(§2.6),.索引处的运行时常量池项必须是对动态计算的调用站点的符号引用(§5.1)。

方便地,javap已经查找常量池并对信息进行解码;结果是在行中的指令后面打印了一个注释。

代码语言:javascript
复制
14: invokedynamic #20,  0             // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;

number #0是您已经发布的BootstrapMethods属性的索引。方法名称的含义取决于该引导方法。此外,还有类型描述符 (I)Ljava/lang/String;,因此这个特定的调用会消耗int并生成String

运行时将发生什么取决于引用的引导方法。这种调用指的是static方法StringConcatFactory.makeConcatWithConstants(...),作为方式的一部分,字符串连接是用Java 9编译的。

这种方法的文档化告诉我们,invokedynamic指令中使用的方法名是无关的,BootstrapMethod属性的静态参数(即text + String: \u0001 )决定字符串格式。\u0001是“普通参数”(即int参数)的位置持有者。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61485900

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档