关于 jit-compilation
面向实现即时编译的 Agent,涵盖 LLVM ORC/LLJIT、Cranelift 和 Rust dynasm,也介绍延迟编译、内联缓存及可执行内存安全。
主要功能
- 01LLVM ORC JIT v2 和 LLJIT 指引
- 02Cranelift JIT 配置
- 03使用跳板实现延迟编译
- 04内联缓存设计
- 05W^X 与 JIT 安全
- 06Rust dynasm x86 代码生成
适用场景
- 01为解释器添加 JIT 热路径
- 02首次调用时编译函数
- 03在 REPL 或游戏引擎中嵌入代码生成
- 04用 Rust 生成 x86 代码片段
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mohitmishra786/ low-level-dev-skills --skill jit-compilation安装后在 Claude Code 中输入/jit-compilation确认已加载。
详细介绍
JIT 编译
用途
指导 Agent 使用即时编译:LLVM ORC JIT v2(ExecutionSession、IRLayer、ObjectLayer)、适用于简单场景的 LLJIT、Cranelift JIT、用于动态分发的内联缓存、用于延迟编译的跳板、安全注意事项(W^X、代码签名),以及用于 x86 代码生成的 Rust dynasm。
适用场景
- 构建带有 JIT 热路径的解释器
- 实现首次调用时的函数延迟编译
- 在 REPL 或游戏引擎中嵌入动态代码生成
- 无需编写完整链接器即可对代码生成进行原型设计
- 为多态调用点创建内联缓存
- 使用 Rust 的
dynasm生成 x86 机器码
工作流
1. JIT 架构概览
Source/AST/Bytecode
→ IR (LLVM IR or Cranelift CLIF)
→ Object file (in memory)
→ Runtime linker (RTDyldObjectLinkingLayer)
→ Executable code in R+X memory
→ Function pointer call
2. LLJIT — 最简单的 LLVM JIT
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/IRBuilder.h"
using namespace llvm;
using namespace llvm::orc;
int main() {
auto JIT = cantFail(LLJITBuilder().create());
LLVMContext Context;
auto M = std::make_unique<Module>("jit", Context);
IRBuilder<> Builder(Context);
// int add(int a, int b) { return a + b; }
Function *AddFn = Function::Create(
FunctionType::get(Builder.getInt32Ty(),
{Builder.getInt32Ty(), Builder.getInt32Ty()}, false),
Function::ExternalLinkage, "add", M.get());
BasicBlock *BB = BasicBlock::Create(Context, "entry", AddFn);
Builder.SetInsertPoint(BB);
auto Args = AddFn->arg_begin();
Value *Sum = Builder.CreateAdd(Args, Args + 1);
Builder.CreateRet(Sum);
cantFail(JIT->addIRModule(ThreadSafeModule(std::move(M), std::make_unique<LLVMContext>())));
auto AddSym = JIT->lookup("add");
auto *AddPtr = (int (*)(int, int))AddSym->getValue();
int result = AddPtr(3, 4); // 7
return 0;
}
clang++ -std=c++17 jit.cpp $(llvm-config --cxxflags --ldflags --libs core orcjit native) -o jit
3. ORC JIT v2 层
ExecutionSession ES;
auto &MainJD = ES.createBareJITDylib("main");
RTDyldObjectLinkingLayer ObjectLayer(
ES, []() { return std::make_unique<SectionMemoryManager>(); });
IRCompileLayer CompileLayer(
ES, ObjectLayer, std::make_unique<TargetMachineBuilder>());
// Add IR module to JITDylib
ThreadSafeModule TSM = ...;
CompileLayer.add(MainJD, std::move(TSM));
// Resolve symbol
auto Sym = ES.lookup({&MainJD}, "my_func");
各层:
- IRLayer — 将 LLVM IR 编译为目标文件
- ObjectLayer — 链接可重定位目标文件
- ExecutionSession — 符号查找和 JITDylib 管理
4. 使用跳板进行延迟编译
First call → trampoline → compile function → patch trampoline → direct call
// Simplified lazy compile on first invocation
void *LazyCompile(const std::string &Name) {
if (!Compiled.count(Name)) {
auto Fn = CompileFromAST(Name);
Compiled[Name] = Fn;
// Patch call site or update function pointer table
}
return Compiled[Name];
}
ORC 支持通过 LazyCallThroughManager 实现延迟再导出和延迟编译。
5. 内联缓存
// Concept: monomorphic call site caches resolved target
// Pseudocode for dynamic language
function call_site(obj, method, args) {
if (obj.class_id === cache.class_id) {
return cache.fn_ptr(args); // fast path
}
cache.class_id = obj.class_id;
cache.fn_ptr = resolve_method(obj, method);
return cache.fn_ptr(args);
}
JIT 会为每种缓存类型生成专用代码;缓存未命中时进行去优化。
6. Cranelift JIT
use cranelift::prelude::*;
use cranelift_jit::{JITBuilder, JITModule};
use cranelift_module::{Linkage, Module};
let isa = cranelift_native::builder().finish(settings::Flags::new(settings::builder()))?;
let jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
let mut module = JITModule::new(jit_builder);
let mut ctx = module.make_context();
ctx.func = Function::with_name_signature(
module.declare_function("add", Linkage::Export, &sig)?,
sig,
);
// ... build IR in ctx.func ...
module.define_function(func_id, &mut ctx)?;
module.finalize_definitions()?;
let code = module.get_finalized_function(func_id);
let add_fn: fn(i32, i32) -> i32 = unsafe { std::mem::transmute(code) };
Cranelift 的编译速度比 LLVM 更快,适合可嵌入式 JIT。
7. 安全 — W^X 策略
W^X (Write XOR Execute)
├── Memory page is writable OR executable, never both
├── JIT: allocate RW → write code → mprotect(RX)
└── macOS hardened runtime requires signed JIT pages
#include <sys/mman.h>
void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
// write machine code to mem
mprotect(mem, size, PROT_READ | PROT_EXEC);
Linux:在 Apple 平台上使用 MAP_JIT;在经过强化的系统上使用 sealed memfd。
8. Rust dynasm(x86)
use dynasm::dynasm;
use dynasmrt::{Assembler, ExecutableBuffer};
let mut asm = Assembler::new().unwrap();
dynasm!(asm
; .arch x86_64
; add:
; add eax, ecx
; ret
);
let buf = asm.finalize().unwrap();
let add_fn: fn(i32, i32) -> i32 = unsafe { std::mem::transmute(buf.ptr(0)) };
适用于不依赖 LLVM 的轻量级汇编代码片段。
9. 决策树
JIT backend choice?
├── Need LLVM optimizations → ORC JIT / LLJIT
├── Fast compile, embeddable → Cranelift
├── Tiny asm snippets → dynasm
└── ML workloads → MLIR → ORC pipeline
常见问题
| 症状 | 原因 | 修复方法 |
|---|---|---|
| 查找时找不到符号 | 名称修饰或未导出 | 使用 C 链接;LLVMExternalLinkage |
| 调用 JIT 代码时发生段错误 | ABI 不匹配 | 匹配调用约定和类型 |
| W^X mmap 失败 | SELinux/grsecurity | 使用 MAP_JIT;检查 dmesg |
| 重新编译后代码仍然过时 | 函数指针指向旧代码 | 使缓存失效;使用跳板 |
| LLVM JIT 编译缓慢 | JIT 中使用了 -O2 | JIT 使用 -O0;仅优化热点路径 |
| Cranelift 验证错误 | CLIF 无效 | 启用 cranelift_codegen::verify_function |
相关技能
skills/compiler-internals/llvm-passes— 在 JIT 前进行优化skills/compiler-internals/compiler-frontend— 将 AST 转为 JIT 输入的 IRskills/compiler-internals/mlir— 将 MLIR 降低为用于 JIT 的 LLVMskills/compilers/llvm— LLVM IR 基础skills/low-level-programming/interpreters— 使用 JIT 的字节码解释器skills/low-level-programming/assembly-x86— 手写汇编的背景知识
评论
支持 Markdown