"コードは書かれるものではなく、生成されるものになる。その瞬間、言語と実行の境界は消える。"
かつてプログラムは「書かれ」「コンパイルされ」「実行される」ものだった。
だが現代の実行環境はそれを許さない。
- JavaScript の高速実行
- Java VM の実行時最適化
- GPU でのオンデマンドシェーダ生成
- WebAssembly におけるコード変換
これらすべてに共通するのが、JIT(Just-In-Time)コンパイルという技術である。
この章では、JITコンパイラの視点から、
アセンブリ命令がいかに“生成される対象”へと変化していったかを探っていく。
JITコンパイルとは何か?
JIT(Just-In-Time)コンパイルは、実行時にソース(または中間表現)から
ネイティブコード(≒アセンブリ)を生成し、即座に実行する仕組み。
通常の流れ:
- バイトコード/中間表現(IR)を解釈
- 実行タイミングでネイティブ命令列を構築
- メモリ上に配置し、実行権限を付与
-
call
またはjmp
によりジャンプ
つまり、コードを「命令」として動的に構築し、即座に実行する世界である。
なぜJITが必要なのか?
- インタプリタのボトルネックを打破したい
- データに最適化された命令列を生成したい
- 動的言語の柔軟性と、ネイティブコードの速度を両立したい
- ランタイム情報(分岐予測、型情報)を活用したい
JITは「万能薬」ではない。
むしろ、「静的な世界では到達できない最適化領域」に踏み込むための設計者の賭けである。
アセンブリでJITを行うとはどういうことか?
JITをアセンブリレベルで理解するには、
**「自分自身のコードを書きながら、メモリに命令を埋め込む」**という行為を伴う。
具体的には:
- ヒープやページに実行権限付きメモリ領域を確保(例:
mmap
withPROT_EXEC
) - 機械語バイト列を手動で書き込む
- 関数ポインタとしてキャストして呼び出す
例(Linux x86_64):
unsigned char code[] = {
0xB8, 0x2A, 0x00, 0x00, 0x00, // mov eax, 42
0xC3 // ret
};
int (*func)() = (int(*)())code;
printf("%d\n", func()); // 出力: 42
ここで 0xB8
は mov eax, imm32
、0xC3
は ret
に対応する。
このように、バイト列をそのまま命令と認識させて実行することができる。
自作JITの設計:基本構造
JITは、以下の4層構造で設計されることが多い:
- 入力(ソース・中間表現)
- 命令選択・レジスタ割り当て(IR→機械語)
- メモリ配置とエミッション(コード書き込み)
- ジャンプ/コールによる実行
アセンブリ生成はこの中で第3層に相当するが、
性能差・命令長・依存性の管理に深く関わるため、全体構造への影響も大きい。
アセンブリJITにおける注意点
-
命令境界の整合性
- x86は可変長命令:書き間違えると即クラッシュ
-
命令キャッシュへの同期
- 一部環境では
__builtin___clear_cache()
が必要
- 一部環境では
-
メモリ保護
-
mmap()
またはVirtualAlloc()
を正しく用いて、PROT_EXEC
を付与
-
-
アライメント
- AVX等では命令アライメントが性能に影響
つまり、アセンブリJITは**単なる“コードを書くだけ”ではなく、
「実行空間そのものを設計する仕事」**でもある。
現実のJIT実装とアセンブリ生成
ランタイム | JITエンジン | 備考 |
---|---|---|
Java JVM | HotSpot | x86命令を生成してメモリ上に配置し実行 |
.NET CLR | RyuJIT | .NETのILをネイティブに変換 |
JavaScript | TurboFan (V8), IonMonkey | ランタイム最適化あり |
WebAssembly | Cranelift, Wasmtime | WASMバイナリをJITで実行 |
LuaJIT | DynASM | アセンブリDSLで命令を構築する軽量JIT |
これらはすべて、アセンブリ生成を“動的に行う”構造を内包している。
つまり、アセンブリは今や**「書かれる」ものではなく、「生成される」もの**なのだ。
アセンブリJITは未来を先読みする設計行為
JITは決して「速くする魔法」ではない。
むしろ:
- 設計と実行の融合
- 構文と最適化の協調
- 構造の再構成
という観点において、
「言語」「実行環境」「アーキテクチャ」のすべてをまたぐ統合設計技術である。
結語:動的に命令が生成される時代に、設計は何を問うか?
アセンブリは、
もはや「職人が書くもの」ではなく、
システムが生成し、設計者が制御する対象となった。
- どの命令をいつ生成するか
- それはどのデータと結びつくのか
- どの瞬間に最適化されるのか
- 誰がその責任を負うのか
これらすべてが、JITの設計によって決まる。
"設計とは、命令を書くことではない。命令がどのように生まれ、実行され、最適化されるかを支配することである。"