我目前正在出于纯学术目的使用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框架对我造成了很大的“损害”。)
有人可以为我指出一些有关执行这三个指令时JVM幕后情况的示例吗? (invokedynamic
的被叫者会期待什么?)
我已经在JVM中实现了invokestatic
...但是我目前无法理解invokedynamic
。
答案 0 :(得分:2)
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方法。之后,您可以在返回的Callsite
对象上调用dynamicInvoker()
,这将为您提供MethodHandle
,然后应为该特定的调用站点进行缓存,然后(最终)调用。
如果您想了解OpenJDK中的实现方式,可以在这里找到实现:http://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/interpreter/bytecodeInterpreter.cpp#l2446
我猜这在项目的早期阶段可能太棘手,所以现在使用-XDstringConcat=inline
编译程序可能会更容易,因为它使用了旧式StringBuilder
串联,实施起来应该更简单。