記事

【手書きで学ぶ JVM 入門】 第1回:Jaspera で最初の一歩

最新の JVM アセンブラ用 Web IDE「Jaspera」を使って,バイト・コードを手書きしてみましょう。JVM に直接命令を与えることで,Java の世界をより深く理解できます。今回は Jaspera の基本的な使い方から。

 こんにちは。​yamad です。

 ​私は​つい​先日​「セキュリティ・キャンプ ミニ 2026 ​(愛知開催)」の​「バイト・コードを​手書きして​君も​ Java 仮想マシンに​なろう!」と​いう​講義に​参加してきました​(この​話は​また​今度詳しく​書こうと​思います)。​ 今回は,​そこで​生まれた​思わぬ​副産物に​ついて​お話いたします。

 皆さんは,​Java の​プログラムが​どのように​動いているのか,​気に​なった​ことは​ありませんか?​  普段書いている​ Java の​ソース・​コードは,​コンパイルすると​「バイト・コード」と​いう​命令列に​なり,​Java 仮想マシン(JVM)で​実行されます。​  と​いう​ことは,​その​命令を​自分で​書けば,​JVM に​直接指示を​出せるわけです。

 ​今回から​始める​「手書きで​学ぶ JVM 入門」では,​実際に​バイト・コードを​書いて​動かしながら,​JVM の​仕組みを​覗いていこうと​思います。​ まずは,​その​ための​道具​「Jaspera」を​紹介しましょう。

IMPORTANT

 な​お,​筆者は​怠惰でありますから,​次回が​いつに​なるかは​分かりません。​  気に​なることが​あったら,​更新を​待たずに,​どんどん​自分で​調べたり試したりしてみてください。​  筆者を​置いて​先に​進んでしまっても,もちろん構いませんよ!

Jaspera に​ついて#

Jaspera のスクリーンショット

 Jaspera とは,JVM バイト・コードを​手書き・実行する​ための​最新 Web IDEです。​ バイト・コードを​手書きする​ための様々な​コード支援機能が​備わっており,​バイト・コードを​学ぶのに​最適な​環境なのであります。

 ここで​いう,​コード支援機能には,​以下のような​ものが​あります:

  • 構文ハイライト: バイト・コードの​命令や​ラベル,​コメントなどを​色分けして​表示します。

  • コード補完: バイト・コードの​命令や​ラベルを​補完してくれます。

  • 高度な​デバッガ: ブレークポイントを​設定して,​ステップ実行や​変数の​値の​確認が​できます。
    ステップ・イン,​ステップ・​オーバー,​ステップ・​アウトなどの​操作も​可能です。

  • 逆アセンブラ: クラス・ファイルを​逆アセンブルして,​有効な​バイト・コードを​表示します。

    NOTE

    デバッガと​連携し,​例えば​標準ライブラリ・クラスへの​ステップ・イン時には​逆アセンブル結果で​表示され,​ ステップ実行が​可能です。

    TIP

    クラス・ファイルが​格納された​ jar ファイルや​ zip ファイルを​ D&D すると,​すべて​逆アセンブルして​表示されます。​一部​ファイル,​一部​命令列の​編集後,​まとめて​ jar/zip ファイルで​保存する​機能も​あります。

  • 命令辞書: バイト・コードの​命令の​一覧を​表示し,​命令の​意味や​オペランドの​種類を​確認できます。
    スタックや​ローカル変数の​動きも​視覚的に​分かりやすく​表示されます。

  • フレーム可視化: コード上の​命令列を​マウスで​ホバーすると,​その​命令に​よって​発生する​フレーム状態の​遷移を​確認できます。
    スタックや​ローカル変数の​状態を​視覚的に​確認できるので,​バイト・コードの​理解が​深まります。

  • 多言語対応: 上記の​すべての​機能と​ IDE の​ UI は,​日,​英,​中,​仏,​西,​伊,​羅​(ラテン語)に​対応しています。

  • 豊富な​テーマ: IDE の​テーマは,​ダーク系,​ライト系,​カラフル系など,​豊富な​テーマを​用意しています。

  • オフライン実行: あらかじめ端末に​ IDE と​実行環境​(約 60MB)を​保存しておく​ことで,​インタネットに​アクセスできない​環境であっても​ IDE を​使用できます。

 太古の​時代から,​バイト・コードを​手書きする​ためには​ Jasmin のような​専用アセンブラを​ローカル環境に​構築して,​いちいちコンパイルして​実行する​必要が​ありました。​ しかし,​Jaspera では​ブラウザだけで​記述から​実行,​デバッグまで​完結できます。

Jaspera が​生まれた​経緯#

 私の​講義では,​受講生の​皆さんに​ JAL 言語を​書いて​もらう​予定でした。​ JAL は​ JVM バイト・コード用の​新しい​アセンブリ言語で,​最新の​ JVM で​動作し,​文法も​ Java 話者と​親和性が​高いと​いう​特徴が​あります。

 JAL は​ Javasm プラグインを​用いて​ IntelliJ IDEA と​連携する​ことで,​IDE に​よる​支援を​受けながら​書ける​ものであります。​ 受講生の​皆さんにも,​当然​これを​使って​もら​おう,と​講義の​3日ほど​前まで​考えて​おりました。

 事前学習と​して​ IDEA の​環境構築を​して​もらったのですが,​その​過程で,​どうやら​最新の​ IntelliJ IDEA は​(あまりにも​リッチすぎて)​当日持ち込んで​もらう​ラップトップで​使うのは​難しい,と​いう​ことが​分かりました。​ プロジェクトを​開くのに​数十秒かかってしまいますし,​1文字打つごとに​小さな​フリーズが​発生してしまうのです。

 ​これは​いけない,と​思い色々​考えた​結果,​Web IDE に​まる​ごと​作り変えてしまう​選択肢に​気が​付きました。

 急遽 GPT-6 Astra に​ Javasm の​ソース・​コードを​丸々​投げて​頼んで​みた​ところ,​それっぽい​ものが​ 40 分で​出来た​ことですから,​そこから​さらに​改良を​重ねて,​最終的に​今の​ Jaspera が​完成しました​(ここまで​一晩です)。

 実際に​講義で​用いてみた​ところ,​受講生・チュータの​方々から​好評を​いただき,​作った​甲斐が​あったなぁ,と​いう​ところであります​(実際に​コードを​書いたのは​ AI ですけどね😂)。

Jaspera を​使ってみよう!#

 さて,​ここからが​本題です。

 Jaspera を​使う​ためには,​まず​ https://jaspera.yamad.jp に​アクセスしてください。​ 読み込みが​終わると,​テーマ設定画面が​表示されますから,​お好きな​テーマを​選びましょう。

テーマ設定画面。VS Dark が選ばれている。 ​(言語は​端末の​設定から​自動で​選ばれます。​もし意図した​ものと​異なる​場合は​ Alt + V を​押し,​一番下の​項目から​設定できます。​)

まずは​ハロー・​ワールド!#

メイン・パネル

 Jaspera を​開くと,​左の​「ファイル・ツリー」に​サンプル・ソースが​いく​つか​表示されます。​ HelloWorld.jal が​選択され,​「エディタ」に​その​ソース・​コードが​表示されていると​思います。

 まずは​実行してみましょう。​右上の​「実行」ボタンを​押下するか,Ctrl + Enterキーを​押下すると​現在開かれている​コードが​実行されます:

こんにちは,JAL!

命令を​理解する​: 命令辞書#

 特に​ JVM バイト・コードに​まだ​慣れていない方は,​或る​命令が​何を​するのか全く​分からないでしょう。​ そこで​ Jaspera には​「命令辞書」が​搭載されており,​選択した​命令の​解説が​ことこまかに​表示されます。​ 右タブ​「命令辞書」から​開いてみましょう。

命令辞書を開いた画面。iadd の解説が表示されている。

 命令辞書には,​命令の​簡単な​説明と​使用例に​加えて,​「実行すると​フレームが​どうなるか」が​図で​表示されます。​ (フレームの​説明は​後述します)

スタックと使用例

TIP

 こんな​感じで,​エディタ内の​命令を​クリックしても,​命令辞書が​開きます!​ GIF

命令を​理解する​: フレーム可視化#

 エディタ内の​命令を​ホバーする​ことで,​その​命令が​フレームに​どう​影響するのかを​把握できます。

NOTE

 フレーム とは,​メソッドを​実行する​ための​専用の​作業領域の​ことです。​主にオペランド・スタックローカル変数配列 で​構成されています。​オペランド・スタックとは,​命令が​扱う​データの​入出力に​使用されるスタックです。
ほとんどの​命令は,​オペランド・スタックに​値を​出し入れする​もので,​一方で​ごく​一部の​命令は​ローカル変数配列の​データを​扱います。​オペランド・スタックを​用いて​計算を​行い,​一連の​計算結果を​ローカル変数配列に​入れて​保存する,と​いう​考え方で​説明できます。

ホバーしてみた

 invokevirtual 命令を​ホバーしてみると,PrintStream オブジェクトと​引数たる​文字列が​スタックから​取り出されている​ことが​一目で​わかります​(厳密には,​それぞれの​オブジェクトへの​参照が​積まれており,​それが​取り出されます)。

命令を​理解する​: デバッガを​使う#

 デバッガを​使うと,​ブレーク・ポイントを​用いて​処理を​止めたり,ステップ実行を​用いて​命令を​1つ​1つ​実行できて​便利です。

デバッグボタン

 ​「HelloWorld」を​開き,​右上の​「実行」ボタン右側の​矢印を​押下し,​開いた​メニューに​ある​「デバッグ」を​押下します。

デバッグ中画面

 そうすると​デバッグが​始まり,invokevirtual 命令に​あるブレーク・ポイントで​実行が​一時​停止されます。

NOTE

ブレーク・ポイントとは,​プログラムの​実行を​指定行数・処理で​一時停止する​機能です。​ 一時停止中に​変数を​覗いたり,​思考を​したりして​バグの​原因を​突き止めるのに​使用します。​ Jaspera では,​行番号と​命令オフセットの​間を​クリックすると,​設置・​削除が​できます。​ ブレーク・ポイント

 デバッグ中には,​画面下部の​デバッグ・メニューが​使用できます;

デバッグメニュー

 左から​次の​操作に​対応します:

  • 再開: ブレーク・ポイント等で​一時停止した​処理を​再開します。
  • ステップ・​オーバ: 次の​命令まで​実行を​進めます。​メソッドを​呼び出す​場合は,​呼び出し先の​処理を​まとめて​実行し,​戻ってきた​ところで​一時停止します。
  • ステップ・イン: メソッドを​呼び出す命令で​一時停止している​とき,​その​メソッドの​中に​潜って​一時​停止します。
  • ステップ・​アウト:現在の​メソッドから​戻るまで​実行を​進め,​呼び出し元で​一時停止します。
  • 停止: ​プログラムの​実行を​停止します。
  • ブレーク・ポイントを​無視: 設置された​すべての​ブレーク・ポイントを​無視して​実行します​(トグル)。

ステップ・​オーバ#

 命令を​1つ​1つ​実行して,​状態遷移を​見てみましょう。​ ブレーク・ポイントで​一時停止した​状態で,​メニュー左から​2番目の​ボタンを​押下すると​⋯⋯

ステップ・オーバ

 このように,​ブレーク・ポイントで​一時停止していた​命令が​実行され,​その​次の​命令で,また​一時​停止します。​ 右側の​「デバッグ」​画面に​表示されている​フレームの​状態も​変わっている​ことが​分かります。

 ステップ・​オーバ 機能を​使用すると,​命令を​1つ​1つ​確認しながら実行できるのです。

ステップ・イン/ステップ・​アウト#

 ステップ・​インは,​次の​命令まで​実行を​進める​操作です。​ メソッドを​呼び出す命令で​使用すると,​呼び出し先の​メソッドに​入って​一時​停止します:

ステップ・イン

NOTE

ステップ・インを​使用すると,​呼び出された​メソッドの​ JAL コードが​表示されます。​ それが​標準ライブラリや​外部の​クラス・ファイルであれば,自動で​ JAL コードへ​逆アセンブルされます。

 ​潜った​メソッドから​復帰したい​場合は,ステップ・​アウトを​使いましょう。

ステップ・アウト

 このように,​現在の​メソッドから​戻るまで​実行が​進み,​呼び出し元で​再び一時​停止します。

プログラムを​書いてみよう!#

 さて,​使い方が​分かった​ところで,​自分でも​命令を​書いてみましょう。​ 今回は,​2 + 3 を​計算して,​その​結果を​表示してみます。

 HelloWorld.jal を​開き,main メソッドの​中身を​次のように​書き換えてください。​ クラスや​メソッドの​宣言は,​そのままで​大丈夫です。

getstatic java/lang/System->out:Ljava/io/PrintStream;
// ...
// ...
iadd
invokevirtual java/io/PrintStream->println(I)V
return

 さて,​このままでは​ iadd 命令が​取る​値が​スタックに​積まれていません。​ コメントの​部分に​何らかの​命令を​入れてあげると​良さそうです。

 他の​ example や​ 命令辞書とにらめっこしながら,​ぜひぜひ実装してみてくださいね!​ ​(答え合わせは​また​今度)

さい​ごに#

今回は,​JVM バイト・コードを​ブラウザで​手書き・実行できる​「Jaspera」を​紹介しました。​ 講義の​ために​急遽作った​ものではありますが,​せっかくなので,​受講生以外の​皆さんにも​使っていただければ​嬉しいです。

 普段 Java を​書いていると,​スタックに​値を​積んだり,​そこから​取り出したりする​処理を​意識する​機会は​あまりないかもしれません。​ 自分で​命令を​書いて,​1つずつ​実行してみると,​いつもの​プログラムが​少し​違って​見えてくると​思います。

 皆さんも,​ぜひバイト・コードを​手書きして​ Java 仮想マシンの​気持ちを​味わってみてください。

 では,​良き Java 仮想マシン・ライフを!