背景
我目前正在用C#编写JVM,纯粹是为了学术目的(将来可能还会构建一个.NET和Java/Scala混合的应用程序(。
上下文
我编写了简单的JAVA类:
public class test
{
public static String hello_world(int i)
{
return "Hello " + i + " World!";
}
}
并将其编译为CCD_ 1。当我用我的反编译器(我已经将其作为JVM的一部分编写(对其进行反编译时,我看到了该方法的以下说明:
iload_0
invokedynamic 2
areturn
当在常量池中查找索引2
处的常量时,我看到一个InvokeDynamic constant条目,其中包含以下数据:
makeConcatWithConstants : (I)Ljava/lang/String;
我想这是有道理的(我更像是一个.NET用户,而不是JAVA用户(。
当使用参数1
执行我的方法hello_world
时,在执行invokedynamic 2
之前,我有以下堆栈:
----TOP---
0x00000001
--BOTTOM--
问题
我的问题是:如何使用invokedynamic
我无法解析方法makeConcatWithConstants
,因为InvokeDynamic常量不会给我任何makeConcatWithConstants
可能所在的提示(请参阅文档(。
堆栈也不包含对堆的引用,指示方法makeConcatWithConstants
可以与哪个实例类型关联。
我通读了test.class
0文档,但我不理解它(也许我被.NET框架"损坏"了很多(
有人能给我举个例子,说明在执行这三条指令时JVM的引擎盖下发生了什么吗?(invokedynamic
的被叫方期望什么等等(?
我已经在JVM中实现了invokestatic
。。。但我目前无法理解CCD_ 13。
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;
因此,要实现这个字节码,必须有一些机制来创建查找对象,然后才能调用引导方法。之后,您可以在返回的Callsite
对象上调用dynamicInvoker()
,这会给您一个MethodHandle
,然后您应该为这个特定的调用站点缓存它,然后(最后(调用它。
如果你想看看这是如何在OpenJDK中实现的,你可以在这里找到实现:http://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/interpreter/bytecodeInterpreter.cpp#l2446
我猜在项目的早期阶段,这可能太棘手了,所以现在用-XDstringConcat=inline
编译程序可能更容易,因为它使用了传统的StringBuilder
级联,实现起来应该更简单。