背景

我目前正在用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是一组常量参数。

LookupStringMethodType的前导参数分别是:具有与呼叫站点相同特权,某些名称和呼叫站点类型的查找对象。其中第一个需要由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串联,实现起来应该更简单。

08-27 14:37