使用“invokedynamic”——幕后发生了什么?

unk*_*656 2 java jvm invokedynamic jvm-bytecode

背景

我目前正在用 C# 编写 JVM,纯粹出于学术目的(也许将来会构建混合的 .NET 和 Java/Scala 应用程序)。

语境

我写了一个简单的JAVA类:

public class test
{
    public static String hello_world(int i)
    {
        return "Hello " + i + " World!";
    }
}
Run Code Online (Sandbox Code Playgroud)

并将其编译成test.class. 当我使用反编译器(我将其编写为 JVM 的一部分)对其进行反编译时,我看到此方法的以下说明:

iload_0
invokedynamic 2
areturn
Run Code Online (Sandbox Code Playgroud)

当在常量池中查找索引处的常量时2,我​​看到一个包含以下数据的 InvokeDynamic-Constant 条目:

makeConcatWithConstants : (I)Ljava/lang/String;
Run Code Online (Sandbox Code Playgroud)

我想这是有道理的(我更像是 .NET 用户而不是 JAVA 用户)。

hello_world当使用参数执行我的方法时1,在执行之前我有以下堆栈invokedynamic 2

----TOP---
0x00000001
--BOTTOM--
Run Code Online (Sandbox Code Playgroud)

问题

我的问题是:我该如何使用invokedynamic
我无法解析该方法makeConcatWithConstants,因为 InvokeDynamic-Constant 没有给我任何makeConcatWithConstants可能位于何处的提示(请参阅文档)。
堆栈也不包含对堆的引用,指示该方法makeConcatWithConstants可以与哪个实例类型关联。

我通读了文档invokedynamic但我不明白它(也许我被 .NET-Framework 严重“损坏”了)。

有人能给我举一些关于执行这三个指令时 JVM 内部发生的事情的示例吗?(被调用者invokedynamic期望什么等)?

我已经invokestatic在我的 JVM 中实现了......但我目前无法理解invokedynamic

Jor*_*nee 5

的想法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!
Run Code Online (Sandbox Code Playgroud)

您可以在其中看到此特定调用站点的引导方法位于StringConcatFactory

它们Method arguments是常量参数的集合。

LookupString和的主要论点MethodType分别是;与调用点具有相同权限、某些名称和调用点类型的查找对象。其中第一个需要由VM在运行时提供,后两个由invokedynamic常量池条目以名称和类型的形式提供:

#2 = InvokeDynamic      #0:#17         // #0:makeConcatWithConstants:(I)Ljava/lang/String;
Run Code Online (Sandbox Code Playgroud)

因此,要实现此字节码,您必须有一些机制来创建查找对象,然后能够调用引导方法。之后,您可以调用dynamicInvoker()返回的Callsite对象,该对象会为您提供一个对象,MethodHandle然后您应该缓存该特定的调用站点,然后(最后)调用。

如果您想了解 OpenJDK 中是如何实现的,您可以在这里找到实现:http://hg.openjdk.java.net/jdk/jdk/file/tip/src/hotspot/share/interpreter/bytecodeInterpreter.cpp #l2446

我猜想这在项目的早期阶段可能太棘手了,所以现在用 编译你的程序可能会更容易-XDstringConcat=inline,因为它使用了遗留的StringBuilder串联,这应该更容易实现。

  • 它本质上是“invokevirtual”的用户可编程版本。事实上,一旦你有了“invokedynamic”,你应该能够在其之上实现所有“invoke*”字节码。引入“invokedynamic”是为了允许 Java 之外的其他语言的实现者享受与 Java 相同的动态调度性能。 (3认同)