JVM/CLR 如何执行 JIT 编译的原生代码?是通过一些代码注入还是通过将代码复制到可执行内存?允许动态代码执行的系统调用是什么?
3 回答
我可以解释我们如何在CACAO VM(一个仅研究 JIT 的 JVM)中做到这一点。首先,将方法的机器代码生成到某个堆分配的内存块中。mmap
编译后,最终的代码长度是已知的,并且使用和标志分配了一块可执行内存PROT_EXEC
(相关CACAO代码在这里)。然后,机器代码被复制到映射区域。之后,许多架构需要一些特定于机器的缓存刷新机制。例如,看一下 PowerPC 64 的缓存刷新功能。值得注意的是,在 i386 和 x86_64 上,没有什么可做的。在这一步之后,处理器准备好执行新生成的代码。或者,可以将已分配的内存页面标记为可执行mprotect
. 请注意mmap
/mprotect
是 Unix 工具。
我不知道Java具体是如何做到的,但一般来说,你会在解释器的指令流中插入“陷阱”操作码。有两个操作码JVM 规范似乎是为此目的量身定制的。
如果您想确定,没有比来源更好的答案了:http: //download.java.net/jdk6/source/
公共语言运行时对每种类型都有一个方法表,其中的条目指向本地代码或指向 JIT 托管代码的本地存根,然后使用指向刚刚创建的本地代码的指针修复方法表。
MSDN在 MethodDesc 部分有更深入的解释
Dave Notario 的这篇博文解释了 CLR JIT 编译器的工作原理。