mcpField
J
jit-compilation

jit-compilation

github.com/mohitmishra786開発269306 回インストール18 週間前に更新
リポジトリ

jit-compilation について

JITコンパイルを実装するエージェント向けのスキルです。LLVM ORC/LLJIT、Cranelift、Rust dynasmに加え、遅延コンパイル、インラインキャッシュ、実行メモリの安全性を扱います。

主な機能

  1. 01LLVM ORC JIT v2とLLJITの解説
  2. 02Cranelift JITの設定
  3. 03トランポリンによる遅延コンパイル
  4. 04インラインキャッシュの設計
  5. 05W^XとJITのセキュリティ
  6. 06Rust dynasmによるx86コード生成

活用シーン

  1. 01インタープリターへのJITホットパス追加
  2. 02初回呼び出し時の関数コンパイル
  3. 03REPLやゲームエンジンへのコード生成の組み込み
  4. 04Rustによるx86コード片の生成

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill jit-compilation

インストール後、Claude Code で/jit-compilationを入力して読み込まれたか確認します。

詳細

JIT コンパイル

目的

ジャストインタイムコンパイルについてエージェントをガイドします。LLVM ORC JIT v2(ExecutionSession、IRLayer、ObjectLayer)、より簡単なユースケース向けの LLJIT、Cranelift JIT、動的ディスパッチ用のインラインキャッシュ、遅延コンパイル用のトランポリン、セキュリティ上の考慮事項(W^X、コード署名)、および x86 コード生成向けの Rust dynasm を扱います。

使用する場面

  • JIT ホットパスを備えたインタープリターを構築する
  • 初回呼び出し時に関数を遅延コンパイルする機能を実装する
  • REPL やゲームエンジンに動的コード生成を組み込む
  • 完全なリンカーを作成せずにコード生成のプロトタイプを作る
  • ポリモーフィックな呼び出し箇所向けのインラインキャッシュを作成する
  • dynasm を使って Rust から 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/grsecurityMAP_JIT を使用し、dmesg を確認します
再コンパイル後に古いコードが実行される古い関数ポインターキャッシュを無効化し、トランポリンを使用します
LLVM JIT のコンパイルが遅いJIT での -O2JIT では -O0 を使用し、ホットパスのみ最適化します
Cranelift の検証エラー無効な CLIFcranelift_codegen::verify_function を有効にします

関連スキル

  • skills/compiler-internals/llvm-passes — JIT の前に最適化する
  • skills/compiler-internals/compiler-frontend — JIT 入力向けに AST から IR に変換する
  • skills/compiler-internals/mlir — JIT 向けに MLIR を LLVM に下げる
  • skills/compilers/llvm — LLVM IR の基礎
  • skills/low-level-programming/interpreters — JIT を使用するバイトコードインタープリター
  • skills/low-level-programming/assembly-x86 — 手書きアセンブリのコンテキスト

コメント