java JVM字节码表示法,注释语法.动态调用 [英] java JVM bytecode notation, comment grammar. InvokeDynamic
问题描述
问题:第14行是什么意思?
Question: What does line 14 means?
使用javap -v -c分解以下代码:
Use javap -v -c to disassembly the following code:
public class test {
static int i = 2;
public static void main(String[] args) {
test x = new test();
System.out.println("text + String: " + i);
}
}
在主函数中,我们得到以下信息:
in the main function we get the following:
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函数.调用的方法是来自类java/io/PrintStream
的println()
,其输入是来自类Ljava/lang/String
的返回值是Void.
So, for example, line 19 means that invokevirtual function from the #24 item in the runtime constant pool. The method invoked is println()
from the class java/io/PrintStream
, its input is from the class Ljava/lang/String
, its return value is Void.
关于第14行,#0保留对BootstrapMethod的引用,并返回其类为CallSite
的Object吗?
然后:
As for line 14, #0 holds the reference to the BootstrapMethod and returns an Object whose class is CallSite
right?
Then:
- #20指向什么?
- 注释
#0:makeConcatWithConstants:(I)Ljava/lang/String;
是什么意思?
- what is #20 pointing to?
- What does the comment
#0:makeConcatWithConstants:(I)Ljava/lang/String;
means?
此外,在哪里可以找到有关Javap反汇编代码语法的更多信息?或正确的关键字是什么? Oracle关于the JVM instruction set
的文档似乎没有清楚地描述注释的含义.
Also, where could I find more about the Javap disassembly code's grammar? or what is the right keyword? Oracle's document about the JVM instruction set
does not seems to describe clearly about the meaning of the comment.
推荐答案
简短版本:Java从Java 9开始就使用invokedynamic来连接字符串.
The short version: Java uses invokedynamic to concatenate strings since Java 9.
让我们细分一下:
Invokedynamic有两个步骤:
Invokedynamic has two steps:
- 首次调用该指令时,将调用bootstrap方法.返回时,呼叫站点将链接到bootstrap方法的结果.
- 后续调用将直接调用目标 MethodHandle .根据所使用的
CallSite
子类,该站点以后可能会重新链接.The CallSite is just a holder for that MethodHandle. Depending on the
CallSite
subclass used the site might be later relinked.如果查看该说明,我们将在最后看到以下内容:
If we look at the instruction, we see the following at the end:
#0:makeConcatWithConstants:(I)Ljava/lang/String;
第一部分(
#0
)的意思是:引导方法#0.
第二部分是名称-传递给bootstrap方法的名称,该名称可能会或可能不会在其中使用.
第三部分是生成目标的方法类型.在我们的例子中:一个采用int
并返回java.lang.String
的方法.The first part (
#0
) means: Bootstrap method #0.
The second part is the name - which is passed to the bootstrap method and may or may not be used there.
The third part is the method type of the resulting target. In our case: A method that takes anint
and returns ajava.lang.String
.如果我们现在看一下引导方法#0,我们会看到方法参考,这里是.
If we now take a look at the bootstrap method #0 we see a method reference, here to StringConcatFactory.makeConcatWithConstants(...). We also see that there is an additional argument: The String
"text + String: \u0001"
.现在,bootstrap方法的工作是返回MethodHandle(在CallSite内部),在这种情况下,它将执行此字符串连接.但是字符串的连接方式(StringBuilder,String.format,字节码旋转,链接MethodHandles ...)对于实际的类而言并不重要.它只希望将字符串连接起来.
The job of the bootstrap method is now to return a MethodHandle (inside a CallSite) which does in this case this string concatenation. But how it does the string concatenation (StringBuilder, String.format, bytecode spinning, chaining MethodHandles...) does not matter for the actual class. It only wants to have Strings concatenated.
让我们尝试手动模仿这种行为.毕竟,bootstrap方法是普通的Java方法:
Let's try to emulate that behavior by hand. After all, the bootstrap method is an ordinary Java method:
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方法,但是对于我们的小示例来说,这已经足够了.)
(The VM does some more stuff, like it remembers the result and would not call the bootstrap method again, but for our small example this is good enough).
这时,我们可以深入了解bootstrap方法是如何工作的.
事实证明:您可以将VM配置为使用不同的策略.
并且它使用java.base
中的特权位置来访问不复制数组的java.lang.String包私有构造函数-如果以后不修改内容,这是安全的.At this point we can take a look under the hood on how the bootstrap method does it's job.
It turns out: You can configure the VM to use different strategies.
And it uses it's privileged position insidejava.base
to access a package private constructor for java.lang.String that doesn't copying the array - which is safe if the contents is not modified afterwards.默认策略是MethodHandle链接.
The default strategy is MethodHandle chaining.
好消息是:如果有人在某个时候编写了更好的策略,您的程序将从中受益-无需重新编译.
The good news is: If someone writes at some point a better strategy, your program will benefit from it - without recompilation.
这篇关于java JVM字节码表示法,注释语法.动态调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!