JIT编译器如何在执行机器代码之前保持领先?

时间:2018-06-18 02:43:50

标签: jvm executable jit machine-code

如果我理解正确,JIT编译器会动态地将代码(通常是字节码)编译成本机代码并将其插入已知内存中的适当位置。

一旦该过程开始,JIT编译器如何保持领先于执行的机器代码?如何确保执行代码不会遇到使用GOTO或同等代码指向的空白内存,因为JIT还没有找到下一步放在那里的内容?

例如,给定一些(假的)字节码:

03 01 move variable 1 onto the stack
b3 02 do something with the contents

在生成第一行本机代码并将其放入下一行以进行运行之后,我假设JIT将为本机代码提供一个" GOTO"一组空的内存,用于运行下一批指令。但是,如果机器代码在JIT编译器有时间将第2行的机器代码放入该插槽之前到达该怎么办?

2 个答案:

答案 0 :(得分:0)

这在特定的实现之间有所不同。可能的策略是在解释器中运行代码,或者在分层JIT的情况下在先前的编译层中运行代码,同时编译或暂停执行直到编译完成。

答案 1 :(得分:0)

通过以下两个规则来确保正确性:

禁止执行未完成的代码

JIT编译器将首先完成对其工作的代码区域的编译,这可能是基本块,函数或对代码的任意跟踪。只有完成后,它才允许处理器执行该代码。因此执行永远不会遇到未完成的翻译。

不生成不确定的跳转

每当JIT编译器遇到一个跳转而离开正在编译的代码区域时,它将生成一个返回到解释器代码的跳转,该解释器代码找出可能在哪里继续执行(可能是通过编译其他代码区域),但是从不一个未定义的位置。在编译区域的末尾执行相同的操作。

一些JIT也可以编译为遵循机器调用约定的函数,因此可以仅使用普通返回(LLVM JIT就是一个例子)。在这种情况下,只需通过函数指针调用“ JITed”代码,该代码就会返回给作为解释器的调用者。

其他JIT编译器会为生成的代码生成自定义的序言和结尾,以确保在执行jit代码后处理器处于定义的状态,并且可以获取继续执行所需的所有信息。

作为优化,JIT可能会注意到跳转到已经JIT编译的代码或静态预编译的代码(例如库函数),然后在其中发出直接跳转,或者他们可以创建跳转指令以后可以对其进行修补,以转至新编译的代码段(QEMU执行此操作)。