java JVM 字节码表示法,注释语法。调用动态
java JVM bytecode notation, comment grammar. InvokeDynamic
问题:第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 项调用虚函数。调用的方法是classjava/io/PrintStream
的println()
,它的输入是classLjava/lang/String
,它的return值为Void。
至于第 14 行,#0 持有对 BootstrapMethod 的引用和 returns 一个对象,其 class 是 CallSite
对吗?
然后:
- #20 指向什么?
- 评论
#0:makeConcatWithConstants:(I)Ljava/lang/String;
是什么意思?
另外,我在哪里可以找到更多关于 Javap 反汇编代码语法的信息?或者什么是正确的关键字? Oracle关于the JVM instruction set
的文档好像没有把注释的意思描述清楚。
简短版本:Java 自 Java 9.
使用 invokedynamic 连接字符串
让我们稍微分解一下:
Invokedynamic 有两个步骤:
- 第一次调用该指令时,会调用bootstrap方法。当它 returns 时,调用站点将链接到 bootstrap 方法的结果。
- 后续调用将直接调用目标MethodHandle。
CallSite 只是 MethodHandle 的持有者。根据使用的 CallSite
subclass,该站点可能会在以后重新链接。
如果我们查看说明,我们会在末尾看到以下内容:
#0:makeConcatWithConstants:(I)Ljava/lang/String;
第一部分(#0
)表示:Bootstrap方法#0。
第二部分是名称 - 传递给 bootstrap 方法,可能会也可能不会在那里使用。
第三部分是结果目标的方法类型。在我们的例子中:采用 int
和 return 的方法 java.lang.String
.
如果我们现在看一下 bootstrap 方法 #0,我们会看到一个方法参考,这里是 StringConcatFactory.makeConcatWithConstants(...)。
我们还看到还有一个额外的参数:The String "text + String: \u0001"
.
bootstrap 方法的工作现在是 return 一个 MethodHandle(在 CallSite 内),它在这种情况下执行此字符串连接。但是它如何进行字符串连接(StringBuilder、String.format、字节码旋转、链接 MethodHandles...)对于实际的 class 并不重要。它只想连接字符串。
让我们尝试手动模拟该行为。毕竟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 的包私有构造函数,该构造函数不复制数组 - 如果之后不修改内容,这是安全的。
默认策略是 MethodHandle 链接。
好消息是:如果有人在某个时候写出更好的策略,您的程序将从中受益——无需重新编译。
First, the unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), ... The run-time constant pool entry at the index must be a symbolic reference to a dynamically-computed call site (§5.1).
方便的是,javap
确实已经查找常量池并解码信息;结果是像行
中指令后面的注释一样打印的内容
14: invokedynamic #20, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
数字#0
是您已经发布的BootstrapMethods
属性的索引。方法名的含义取决于那个bootstrap方法。此外还有 type descriptor (I)Ljava/lang/String;
,所以这个特定的调用消耗了一个 int
并产生了一个 String
.
运行时会发生什么取决于引用的 bootstrap 方法。此调用引用 static
方法 StringConcatFactory.makeConcatWithConstants(...)
,部分方式,字符串连接是用 Java 9.
编译的
documentation of that method 告诉我们 invokedynamic
指令中使用的方法名称是无关紧要的, BootstrapMethod
属性的静态参数,即 text + String: \u0001
决定了字符串格式。 \u0001
是“普通参数”的占位符,即 int
参数。
问题:第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 项调用虚函数。调用的方法是classjava/io/PrintStream
的println()
,它的输入是classLjava/lang/String
,它的return值为Void。
至于第 14 行,#0 持有对 BootstrapMethod 的引用和 returns 一个对象,其 class 是 CallSite
对吗?
然后:
- #20 指向什么?
- 评论
#0:makeConcatWithConstants:(I)Ljava/lang/String;
是什么意思?
另外,我在哪里可以找到更多关于 Javap 反汇编代码语法的信息?或者什么是正确的关键字? Oracle关于the JVM instruction set
的文档好像没有把注释的意思描述清楚。
简短版本:Java 自 Java 9.
使用 invokedynamic 连接字符串让我们稍微分解一下:
Invokedynamic 有两个步骤:
- 第一次调用该指令时,会调用bootstrap方法。当它 returns 时,调用站点将链接到 bootstrap 方法的结果。
- 后续调用将直接调用目标MethodHandle。
CallSite 只是 MethodHandle 的持有者。根据使用的 CallSite
subclass,该站点可能会在以后重新链接。
如果我们查看说明,我们会在末尾看到以下内容:
#0:makeConcatWithConstants:(I)Ljava/lang/String;
第一部分(#0
)表示:Bootstrap方法#0。
第二部分是名称 - 传递给 bootstrap 方法,可能会也可能不会在那里使用。
第三部分是结果目标的方法类型。在我们的例子中:采用 int
和 return 的方法 java.lang.String
.
如果我们现在看一下 bootstrap 方法 #0,我们会看到一个方法参考,这里是 StringConcatFactory.makeConcatWithConstants(...)。
我们还看到还有一个额外的参数:The String "text + String: \u0001"
.
bootstrap 方法的工作现在是 return 一个 MethodHandle(在 CallSite 内),它在这种情况下执行此字符串连接。但是它如何进行字符串连接(StringBuilder、String.format、字节码旋转、链接 MethodHandles...)对于实际的 class 并不重要。它只想连接字符串。
让我们尝试手动模拟该行为。毕竟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 的包私有构造函数,该构造函数不复制数组 - 如果之后不修改内容,这是安全的。
默认策略是 MethodHandle 链接。
好消息是:如果有人在某个时候写出更好的策略,您的程序将从中受益——无需重新编译。
First, the unsigned indexbyte1 and indexbyte2 are used to construct an index into the run-time constant pool of the current class (§2.6), ... The run-time constant pool entry at the index must be a symbolic reference to a dynamically-computed call site (§5.1).
方便的是,javap
确实已经查找常量池并解码信息;结果是像行
14: invokedynamic #20, 0 // InvokeDynamic #0:makeConcatWithConstants:(I)Ljava/lang/String;
数字#0
是您已经发布的BootstrapMethods
属性的索引。方法名的含义取决于那个bootstrap方法。此外还有 type descriptor (I)Ljava/lang/String;
,所以这个特定的调用消耗了一个 int
并产生了一个 String
.
运行时会发生什么取决于引用的 bootstrap 方法。此调用引用 static
方法 StringConcatFactory.makeConcatWithConstants(...)
,部分方式,字符串连接是用 Java 9.
documentation of that method 告诉我们 invokedynamic
指令中使用的方法名称是无关紧要的, BootstrapMethod
属性的静态参数,即 text + String: \u0001
决定了字符串格式。 \u0001
是“普通参数”的占位符,即 int
参数。