
2026/03/10 18:31
**タイトル** 「JITで生成したコードを世に知れ渡らせる ― その手段を数え上げてみよう」
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
(必要に応じて修正がない場合は元の要約をそのまま繰り返してください)
Summary:
MoarVM, written in C, implements Raku exception handling withrather than standard C++ unwind tables. On Windows, MSVC’s change to fully unwind frames broke crash handling because JIT‑compiled code had no unwind info. The fix was to generate unwinding data for those frames and register it via the WinAPI calllongjmp, which stops crashes but still leaves gaps in debugging support.RtlAddFunctionTableThe author has examined several cross‑platform APIs:
•’slibunwindfor naming functions and supplying unwind tables._U_dyn_register
• GDB’s “jitreader” plugin (,__jit_debug_descriptor) for complete debug info (name, file, line).__jit_debug_register_code
• Linux perf’s JITDUMP format, which records machine‑code blobs with timestamps and optional source data.
Since September 2018 MoarVM has used Perf Map to list function names, addresses, and lengths, but this approach lacks an assembly view.Additional possibilities include creating loadable ELF/DLLs and loading them via
(providing full debugging support at the cost of I/O overhead) or exposing JIT functions to Valgrind client requests for callgrind/cachegrind.dlopen
The overarching aim is a single, cross‑platform solution that supplies naming, unwinding, source mapping, and disassembly for MoarVM’s JIT code—improving crash diagnostics, performance profiling, and the overall developer experience, and potentially serving as a model for other JIT runtimes.
本文
AOT コンパイラ
長い間、AOT(Ahead‑Of‑Time)コンパイルで生成されるマシンコードは、ターゲットシステムのさまざまな部分で使用することを想定したメタデータとともに出力されるのが当たり前でした。
関数名としてシンボルが付与されており、これによってインストラクションポインタから現在実行中の関数名や開始位置を取得できます。また、DLL・dylib・so といった動的ライブラリをロードした際に、そのシンボルがあれば呼び出したい関数を実際に呼ぶことも可能です。
さらにデバッグ情報として、行番号アノテーションがあります。これによりインストラクションポインタから関数名だけでなく、ファイル名と行番号までマッピングできます。
C++ のような例外機構を持つ言語では、スタック上の各フレームが投げられた例外をどのように処理すべきかを記述したテーブルが出力されます。アンウインド時には、そのテーブルがランタイムライブラリに対し「正しくスタックフレームを破棄するために何をすべきか」を伝え、リソース解放やデストラクタの実行などを行います。
MoarVM は C で書かれているので、C++ スタイルの例外は使いません。代わりに
longjmp(MVM_exception_throw_adhoc 経由)を利用して、呼び出しスタックの奥からインタプリタループへ戻ります。Windows では MSVC の変更により longjmp が常にフレーム単位で完全にアンウインドされるようになりました。純粋な C コードなら問題ありませんが、MoarVM の JIT は longjmp が発生したときにスタック上にフレームを残すことがあります。その際に JIT にはアンウインド情報が無いためクラッシュしてしまいました。
私は必要なアンウインド情報を WinAPI(
RtlAddFunctionTable)へ登録する修正を行いました。Patrick Böker(Lazymio に感謝)の簡易パッチも機能します;彼のプルリクエストをご覧ください。
JIT がシステムに伝えるべき情報
| API | 何を提供するか | 備考 |
|---|---|---|
| Windows 用アンウインド情報 | シンボル名は含まれない |
| シンボル名+アンウインドテーブル | 自分のスタックだけを歩く場合に有効 |
| GDB “jitreader” | 完全なデバッグ情報(名前・ファイル・行) | 手動で plumbing 必要、重い |
| JITDUMP フォーマット | シンボル名+アンウインドテーブル+行番号 | で後処理が必要 |
| Perf Map | 簡易テキスト:アドレス・サイズ・名前 | 最も簡単;アセンブリは表示できない |
速くてシンプル:Perf Map
“Perf Map” ファイルは予測可能なパスにある単一のテキストファイルです。
各行は次の形式で構成されます。
<address> <size> <function_name>
perf report はこれを利用して関数名とソースファイル名を出力できますが、実際のアセンブリコードを表示することはできません。
高度:RtlAddFunctionTable / libunwind
両 API は似ています。フレームごとのアンウインド方法を記述したテーブルを登録します。
Windows では
RtlAddFunctionTable、Linux では _U_dyn_register を使用します。アドレス空間とオフセットの取り扱いには注意が必要です。
強力だが冗長:GDB JIT Reader
GDB はグローバルシンボル
__jit_debug_descriptor を調べます。__jit_debug_register_code を呼び出すと、JIT のデバッグ情報を含むメモリブロック(symfile)を渡します。バイト読み取り関数、オブジェクト作成関数、シンボルテーブル・ブロック・行マッピングの実装が必要です。
GDB プラグインは JIT コードをデバッグセッションに注入し、ファイル/ライン情報付きでバックトレースできるようにします:
#6 0x00007ffff746a483 in MVM_io_write_bytes ... at src/io/io.c:178 #7 0x00007ffff575cb3e in spurt () ... at SETTING::src/core.c/IO/Handle.rakumod:7
JITDUMP フォーマット
JITDUMP は
perf が理解するバイナリフォーマットです。
- ファイル(通常は実行ファイルの隣)を開く。
- モノトニッククロック値を含むヘッダーを書き込む。
- 各コードブロックについて、アドレス・サイズ・マシンコード全体とタイムスタンプを前置して書き込む。
その後、次のように実行します:
perf record -k 1 -e cpu-clock ./your_program perf inject --jit your_jitdump_file perf.data > perf.jit.data
perf report は JIT コンパイルされた関数のディスアセンブルを表示できるようになります。
その他ツール
- Valgrind – クライアントリクエストでメモリ使用量、カスタムアロケータ等に注釈を付けられます。
Callgrind/Cachedgrind の可視化には便利ですが、ドキュメントは乏しいです。
結論
JIT からデバッグ・アンウインド情報を露出する方法はいくつかあります:
- Perf Map(シンプルでアセンブリは表示不可)
- RtlAddFunctionTable /
(アンウインドテーブルのみ)_U_dyn_register - GDB jitreader(完全なデバッグ情報、設計が重い)
- JITDUMP(perf 統合、後処理必要)
統一的な解決策はまだありません。ニーズに合わせて最適なものを選択してください。
ご意見やソリューションがあれば、 libera.chat の
timo か Fediverse でお気軽にどうぞ。