java - 使用 "invokedynamic"- 幕后发生了什么?

标签 java jvm jvm-bytecode invokedynamic

背景

我目前正在用 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 用户)。

当使用参数1执行我的方法hello_world时,在执行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

方法参数是一组常量参数。

Lookup 的主要论点、字符串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 连接,应该更容易实现。

关于java - 使用 "invokedynamic"- 幕后发生了什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53139737/

相关文章:

Java JNA 解引用指针

java - 在 Android 中使用 JCIFS

Java:JFrame 分辨率?

java - Linux JVM 上对象的内在锁

java - 如何使用 ByteBuddy 创建动态代理

java - 通过 TestNG 和 Eclipse 运行 Webdriver 时出现参数 BROWSER 丢失错误

java - 了解 Java 中的类加载器

garbage-collection - 尽管 NewRatio=2,年轻代仍然很小

javac 生成一个桥接方法,其中包含指向抽象方法的 invokespecial 指令

java - 如何创建一个 ASM LdcInsnNode 将当前类静态添加到堆栈中?