はじめに
JAL(JVM Assembly Language)は,Java 仮想マシン(JVM)の命令を記述するアセンブリ言語です。.jal ファイルにクラスと命令列を書き,コンパイラで .class ファイルへ変換します。
Java の System.out.println(...) も,JAL では値を積む命令とメソッドを呼ぶ命令に分けて書きます。Java の構文を知っていれば,見慣れた処理とバイトコードの対応を調べる題材になります。JVM 固有の用語は各ページで説明します。
ドキュメントで読み,Jaspera で試す
このサイトは JAL の書き方を調べるドキュメントです。Jaspera は,JAL の編集・コンパイル・実行をブラウザ内で行うサンドボックスです。ステップ実行で停止し,オペランドスタックやローカル変数の値を確認できます。
まず試すなら チュートリアル へ進んでください。CLI や IntelliJ IDEA を使う場合は ツールの導入 に手順があります。
HelloWorld
public class HelloWorld (major_version=55, minor_version=0) {
public static main([Ljava/lang/String;)V {
getstatic java/lang/System->out:Ljava/io/PrintStream;
ldc "Hello, World!"
invokevirtual java/io/PrintStream->println(Ljava/lang/String;)V
return
}
}
getstatic が System.out の参照を積み,ldc が文字列を積みます。invokevirtual はこの二つを使って println を呼び,return が main を終了します。
([Ljava/lang/String;)V は「String[] を一つ受け取り,値を返さない」というメソッド記述子です。major_version=55 は Java 11 のクラスファイル形式を指定しています。実行には,その形式と使用する API に対応した JVM が必要です。
コンパイラが行うこと
JAL では,分岐先にラベルを使い,フィールドやメソッドを名前と型で参照します。コンパイラがそれらをクラスファイルの形式へ変換し,通常の設定では検証用のスタックマップも生成します。命令の順番や値の型が誤っている場合は,ソースの修正が必要です。
JVM バイトコードは仮想マシンの命令です。CPU のレジスタや OS の呼び出し規約を直接指定する言語ではありません。まず クラスファイルの見方 で,何を記述しているのかを確認できます。