如果我理解正确,JIT编译器会动态地将代码(通常是字节码)编译成本机代码并将其插入已知内存中的适当位置。
一旦该过程开始,JIT编译器如何保持领先于执行的机器代码?如何确保执行代码不会遇到使用GOTO或同等代码指向的空白内存,因为JIT还没有找到下一步放在那里的内容?
例如,给定一些(假的)字节码:
03 01 move variable 1 onto the stack
b3 02 do something with the contents
在生成第一行本机代码并将其放入下一行以进行运行之后,我假设JIT将为本机代码提供一个" GOTO"一组空的内存,用于运行下一批指令。但是,如果机器代码在JIT编译器有时间将第2行的机器代码放入该插槽之前到达该怎么办?
答案 0 :(得分:0)
这在特定的实现之间有所不同。可能的策略是在解释器中运行代码,或者在分层JIT的情况下在先前的编译层中运行代码,同时编译或暂停执行直到编译完成。
答案 1 :(得分:0)
通过以下两个规则来确保正确性:
禁止执行未完成的代码
JIT编译器将首先完成对其工作的代码区域的编译,这可能是基本块,函数或对代码的任意跟踪。只有完成后,它才允许处理器执行该代码。因此执行永远不会遇到未完成的翻译。
不生成不确定的跳转
每当JIT编译器遇到一个跳转而离开正在编译的代码区域时,它将生成一个返回到解释器代码的跳转,该解释器代码找出可能在哪里继续执行(可能是通过编译其他代码区域),但是从不一个未定义的位置。在编译区域的末尾执行相同的操作。
一些JIT也可以编译为遵循机器调用约定的函数,因此可以仅使用普通返回(LLVM JIT就是一个例子)。在这种情况下,只需通过函数指针调用“ JITed”代码,该代码就会返回给作为解释器的调用者。
其他JIT编译器会为生成的代码生成自定义的序言和结尾,以确保在执行jit代码后处理器处于定义的状态,并且可以获取继续执行所需的所有信息。
作为优化,JIT可能会注意到跳转到已经JIT编译的代码或静态预编译的代码(例如库函数),然后在其中发出直接跳转,或者他们可以创建跳转指令以后可以对其进行修补,以转至新编译的代码段(QEMU执行此操作)。