当前位置: 首页 > 知识库问答 >
问题:

使用“invokedynamic”--在引擎盖下发生了什么?

太叔坚
2023-03-14

我目前正在用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时,在执行invokedynamic2之前,我有以下堆栈:

----TOP---
0x00000001
--BOTTOM--

我通读了invokedynamic文档,但我不理解它(也许我被.NET Framework“损坏”了很多)。

有人能给我举个例子,说明JVM在执行这三条指令时的情况吗?(invokedynamic的被调用方期望什么,等等)?

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

共有1个答案

阎渝
2023-03-14

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!

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

lookupstringmethodtype的前导参数分别是;具有与callsite相同的PriveEdges、某些名称和callsite的类型的查找对象。其中第一个需要由VM在运行时提供,后两个由invokedynamic常量池条目以名称和类型的形式提供:

#2 = InvokeDynamic      #0:#17         // #0:makeConcatWithConstants:(I)Ljava/lang/String;

因此,要实现这个字节码,您必须有一些机器来创建查找对象,然后才能调用引导方法。之后,您可以在返回的callsite对象上调用DynamicInvoker(),该对象为您提供了一个MethodHandle,然后您应该为这个特定的callsite缓存该对象,然后(最后)调用该对象。

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

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

 类似资料:
  • 问题内容: 我一直在尝试React Hooks,它们似乎确实简化了诸如存储状态之类的事情。但是,他们似乎通过魔术来做很多事情,而我找不到关于它们实际工作方式的好文章。 看起来很神奇的第一件事是,每次调用setXXX方法时,调用诸如useState()之类的函数如何导致功能组件的重新渲染? 当功能组件甚至没有能力在Mount / Unmount上运行代码时,诸如useEffect()之类的东西如何伪

  • 我一直在尝试React钩子,它们似乎可以简化存储状态之类的事情。然而,他们似乎用魔法做了很多事情,我找不到一篇关于他们如何实际工作的好文章。 第一件看起来很神奇的事情是,调用像useState()这样的函数是如何在每次调用setXXX方法时导致函数组件的重新渲染的? 当功能组件甚至不具备在挂载/卸载上运行代码的能力时,像use效应()这样的东西是如何伪造组件的? useContext()实际上是如

  • 我想在我的项目中使用Spring Data Elasticsearch,我看到了这一点: 我的方法是只使用Spring数据Elasticsearch来执行CRUD操作(类似ORM),使用高级REST客户端进行搜索和所有其他操作。因此,我想知道ElasticsearchRepository使用哪个客户端来执行其操作,以及代码是否在Elasticsearch的8.0版中不再有效 使用3.1.5版仍然是

  • 我必须评估Codename One,但我找不到关于部署在底层是如何工作的以及最终结果是什么的信息。他们是否将我的Java代码交叉编译为类似于RoboVM的真实本机代码,他们是否使用类似于Gluon的JVM,或者他们有自己的JVM?

  • 您都知道将依赖项放入pom.xml文件并运行“MVN clean Install”的过程。当这个命令运行时,依赖项的jar文件被下载到。m2存储库中。 当我们使用IntelliJ和run/debug配置窗口运行应用程序时,IntelliJ如何知道在哪里查找依赖项的jar文件?IntelliJ中的每个GUI操作实际上都取代了命令行操作。当我们单击“运行”按钮时,在“幕后”提交的命令行操作是什么。我相

  • 问题内容: 在阅读了戴夫·切尼(Dave Cheney)关于Go的地图的博客文章之后,对我来说,还有几件事尚不清楚。 TLDR: 为什么它们无序? 实际值存储在哪里? 深入研究运行时程序包后,我发现基本的映射结构如下: -是存储区数组,其中索引是键的哈希值的低位,其中存储区为: ..好吧,这只是每个项目是键的哈希值的第一个字节的数组。键值对存储为(每个存储桶八对)。但是到底在哪里?考虑到映射可能包