chn*_*nnn 4 java jvm javap jvm-bytecode
问题:第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);
}
}
Run Code Online (Sandbox Code Playgroud)
在主函数中,我们得到以下内容:
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
Run Code Online (Sandbox Code Playgroud)
因此,例如,第 19 行表示来自运行时常量池中 #24 项的 invokevirtual 函数。调用的方法println()来自于类java/io/PrintStream,其输入来自于类Ljava/lang/String,其返回值为 Void。
至于第 14 行,#0 持有对 BootstrapMethod 的引用并返回一个对象,其类是CallSite正确的?然后:
#0:makeConcatWithConstants:(I)Ljava/lang/String;是什么意思?另外,我在哪里可以找到有关 Javap 反汇编代码语法的更多信息?或者什么是正确的关键字?Oracle 的文档 aboutthe JVM instruction set似乎没有清楚地描述注释的含义。
简短版本:自 Java 9 以来,Java 使用调用动态来连接字符串。
让我们把它分解一下:
Invokedynamic 有两个步骤:
该调用点仅仅是一个持有人MethodHandle。根据所使用的CallSite子类,该站点以后可能会重新链接。
如果我们查看指令,我们会在最后看到以下内容:
#0:makeConcatWithConstants:(I)Ljava/lang/String;
Run Code Online (Sandbox Code Playgroud)
第一部分 ( #0) 表示:Bootstrap 方法 #0。
第二部分是名称——它被传递给引导方法,可能会或可能不会在那里使用。
第三部分是结果目标的方法类型。在我们的例子中:一个接受 anint并返回 a 的方法java.lang.String。
如果我们现在看看引导方法 #0,我们会看到一个方法引用,这里是StringConcatFactory.makeConcatWithConstants(...)。我们还看到还有一个额外的参数: String "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);
}
Run Code Online (Sandbox Code Playgroud)
(VM 会做更多的事情,比如它会记住结果并且不会再次调用 bootstrap 方法,但对于我们的小例子来说,这已经足够了)。
在这一点上,我们可以深入了解 bootstrap 方法是如何工作的。
事实证明:您可以配置 VM 以使用不同的策略。
并且它使用它在内部的特权位置java.base来访问 java.lang.String 的包私有构造函数,该构造函数不复制数组 - 如果之后不修改内容,这是安全的。
默认策略是 MethodHandle 链接。
好消息是:如果有人在某个时候编写了更好的策略,您的程序将从中受益——无需重新编译。
| 归档时间: |
|
| 查看次数: |
145 次 |
| 最近记录: |