背景
我目前正在用C#编写JVM,纯粹是出于学术目的(也许将来会构建混合的.NET和Java / Scala应用程序)。
语境
我编写了简单的JAVA类:
public class test
{
public static String hello_world(int i)
{
return "Hello " + i + " World!";
}
}
并将其编译为
test.class
。当我用反编译器(作为JVM的一部分编写)对其进行反编译时,我会看到以下有关此方法的说明:
iload_0
invokedynamic 2
areturn
当在常量池中的索引
2
中查找常量时,我看到一个InvokeDynamic-Constant条目,其中包含以下数据:makeConcatWithConstants : (I)Ljava/lang/String;
我猜这是有道理的(我是.NET用户,而不是JAVA用户)。
使用参数
hello_world
执行方法1
时,在执行invokedynamic 2
之前我具有以下堆栈:----TOP---
0x00000001
--BOTTOM--
题
我的问题是:如何使用
invokedynamic
?我无法解析方法
makeConcatWithConstants
,因为InvokeDynamic-Constant不会给我任何提示,makeConcatWithConstants
可能位于其中(see documentation)。堆栈也不包含对堆的引用,该引用指示方法
makeConcatWithConstants
可以与哪种实例类型关联。我通读了the
invokedynamic
docs,但我不明白(也许我对.NET-Framework造成了很大的“损害”)。有人可以指出一些有关执行这三条指令时JVM幕后情况的例子吗? (
invokedynamic
的被呼叫者会期望什么?)?我已经在JVM中实现了
invokestatic
...但是我目前无法理解invokedynamic
。 最佳答案
invokedynamic
的思想是;首次遇到此字节码时,调用引导程序方法,该方法会创建一个Callsite
对象,该对象链接到需要调用的实际方法。
实际上,这通常意味着您为调用动态创建实现。
如果使用javap -v test
查看程序,则会在底部看到BootstrapMethods
属性:
BootstrapMethods:
0: #15 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:
#16 Hello \u0001 World!
在此可以看到此特定呼叫站点的引导方法位于
StringConcatFactory
中Method arguments
是一组常量参数。Lookup
,String
和MethodType
的前导参数分别是:具有与呼叫站点相同特权,某些名称和呼叫站点类型的查找对象。其中第一个需要由VM在运行时提供,后两个需要由invokedynamic常量池条目以名称和类型的形式提供:#2 = InvokeDynamic #0:#17 // #0:makeConcatWithConstants:(I)Ljava/lang/String;
因此,要实现此字节码,您必须具备一些机制来创建查找对象,然后能够调用bootstrap方法。之后,您可以在返回的
dynamicInvoker()
对象上调用Callsite
,这将为您提供MethodHandle
,然后应为该特定的调用站点进行缓存,然后(最终)调用。如果您想看一下如何在OpenJDK中实现它,可以在这里找到实现:http://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/interpreter/bytecodeInterpreter.cpp#l2446
我猜这在项目的早期阶段可能太棘手了,所以就目前而言,使用
-XDstringConcat=inline
编译程序可能会更容易,因为它使用传统的StringBuilder
串联,实现起来应该更简单。