制作 JIT 编译器
Making a JIT compiler
我写了一个Brainfuck实现(C++),工作原理如下:
- 读取输入脑文件
- 进行琐碎的优化
- 将大脑转换为虚拟机的机器代码
- 在 VM 中执行此机器代码
这非常快,但现在瓶颈在 VM 上。它是用C++编写的,读取一个令牌,执行一个动作(如果你知道Brainfuck的话,这根本不多)等等。
我想做的是剥离 VM 并动态生成本机机器代码(所以基本上是一个 JIT 编译器)。这很容易实现 20 倍的加速。
这意味着步骤 3 被 JIT 编译器取代,步骤 4 被执行生成的机器代码所取代。
我不知道从哪里开始,所以我有几个问题:
- 这是如何工作的,生成的机器代码是如何执行的?
- 是否有用于生成本机机器代码的C++库?
-
生成的机器代码只是像往常一样
jmp
-ed 或call
-ed。有时它还需要在包含生成代码的内存上禁用无执行标志(NX 位)。在 Linux 中,这是通过mprotect(addr, size, PROT_READ | PROT_WRITE | PROT_EXEC.)
在 Windows 中,NX 称为 DEP。 -
有一些...例如 http://www.gnu.org/software/lightning/- GNU Lightning(通用)和 https://developer.mozilla.org/En/Nanojit - Nanojit,用于Firefox JavaScript JIT引擎。更强大和现代的JIT是LLVM,你只需要将BF代码转换为LLVM IR,然后LLVM就可以对许多平台进行优化和代码生成,或者在具有JIT功能的解释器(虚拟机)上运行LLVM IR。有一篇关于BF和LLVM的文章,它为BF http://www.remcobloemen.nl/2010/02/brainfuck-using-llvm/提供了完整的LLVM JIT编译器
。
另一个BF + LLVM编译器在这里,在LLVM的svn中:https://llvm.org/svn/llvm-project/llvm/trunk/examples/BrainF/BrainF.cpp
LLVM是一个完整的C++库(或一组库),用于从中间形式生成本机代码,包括文档和示例,并已用于生成JITter。
(它还有一个使用该框架的C/C++编译器 - 但是框架本身可用于其他语言)。
这可能已经晚了,但为了帮助任何其他人,我发布了这个答案。
JIT 编译器具有 AOT 编译器具有的所有步骤。主要区别在于 AOT 编译器将机器相关代码输出到可执行文件(如 exe 等),而 JIT 编译器在运行时将计算机相关代码加载到内存中(因此性能开销,因为每次都需要重新编译和加载)。
JIT 编译器如何在运行时将机器代码加载到内存中?
我不会教你机器代码,因为我假设你已经知道它,
例如汇编代码
mov rax,0x1
被翻译成
48 c7 c0 01 00 00 00
您动态生成翻译后的代码并将其保存到这样的向量中(这是一个 C 向量)
vector machineCode{
0x48, 0xc7, 0xc0, 0x01, 0x00, 0x00, 0x00,
}
然后你把这个向量复制到内存中,为此你需要知道这个代码所需的内存大小,你可以通过machinecode.size()获得,并记住页面大小。
要将此向量复制到内存中,您需要在 C 中调用 mmap 函数。将指针设置为代码的开头并调用它。你很好去。
抱歉,如果有什么不清楚的地方,为了简单起见,您可以随时查看这篇文章https://solarianprogrammer.com/2018/01/10/writing-minimal-x86-64-jit-compiler-cpp/https://github.com/spencertipping/jit-tutorial
GNU Lightning 是一组宏,可以为几种不同的架构生成本机代码。 您将需要对汇编代码有深入的了解,因为您的步骤 3 将涉及使用 Lightning 宏将机器代码直接发送到稍后将执行的缓冲区中。
- C/C++编译器通常会删除重复的库吗
- 模板-模板参数推导:三个不同的编译器三种不同的行为
- Win32编译器选项和内存分配
- MSVC多行宏编译器错误
- 静态数据成员的问题-修复链接错误会导致编译器错误
- C++,我收到一个无法理解的编译器错误
- 在线编译器中的分段C++没有打印消息
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- C/C++预处理器是否可以检测一些编译器选项
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- C++错误C2600:无法定义编译器生成的特殊成员函数(必须首先在类中声明)
- 我需要知道编译器如何在cpp中使用析构函数
- 编译器如何区分std::vector的构造函数
- CLANG 编译器 说:变量"PTR"可能未初始化
- JIT 编译器及其在 C++ 前面加快 .NET 中程序执行速度的好处
- 编译器/JIT 优化 Java 和 C++ 中 for 循环的边界检查
- 我可以为c#制作自己的JIT解释器编译器并在Visual Studio中使用它吗?
- 编写JIT编译器时存储代码常量的位置
- JIT编译器和异常处理
- 制作 JIT 编译器