メインコンテンツまでスキップ
Java Assembly Language

JVM バイトコードを,
自分で書く。

JAL(Java Assembly Language)は,JVM の命令を直接書くためのアセンブリ言語です。 LangJAL のコンパイラで .jal ファイルを .class に変換し,Java と同じ JVM で実行できます。

足し算も,メソッドの呼び出しも,スタックへの値の出し入れから。 この例では,引数を2倍にして返しています。

.jal → .class
JVM バイトコードを生成
CLI / Gradle
ローカルでコンパイル
IntelliJ
Javasm による編集支援
1public static twice(I)I {2iload_0実行後の状態スタック
  1. value
ローカル変数
  1. 0: value
3iconst_2実行後の状態スタック
  1. value
  2. 2
ローカル変数
  1. 0: value
4imul実行後の状態スタック
  1. value * 2
ローカル変数
  1. 0: value
5ireturn6}
Language

LangJAL でできること

01

命令を直接書く

iload,iadd,invokevirtual。Java の式や文の代わりに,JVM が実行する命令を並べてプログラムを組み立てます。

02

StackMapFrame を自動生成

通常のコンパイルでは,検証に使う型情報を命令列から生成します。分岐の合流点で必要な条件は,言語ガイドで説明します。

03

クラスファイルを読み戻す

逆アセンブラ jalp で .class を JAL に変換できます。Java のソースがどのような命令に変わったのかを調べられます。

Syntax

命令を並べて,繰り返す

ラベルを付けてジャンプすると,分岐や繰り返しを表せます。 この例は,引数の整数を表示するたびに 1 減らし,0 以下になると終了します。

命令リファレンスへ
1public static countdown(I)V {2Loop:3iload_0実行後の状態スタック
  1. count
ローカル変数
  1. 0: count
4ifle Done実行後の状態スタックローカル変数
  1. 0: count
5getstatic java/lang/System->out:Ljava/io/PrintStream;実行後の状態スタック
  1. System.out
ローカル変数
  1. 0: count
6iload_0実行後の状態スタック
  1. System.out
  2. count
ローカル変数
  1. 0: count
7invokevirtual java/io/PrintStream->println(I)V実行後の状態スタックローカル変数
  1. 0: count
8iinc 0 -1実行後の状態スタックローカル変数
  1. 0: count - 1
9goto Loop10Done:11return12}
Workflow

ブラウザで動かすなら,Jaspera。

Jaspera は,JAL を編集・実行できるサンドボックスです。インストールせずにサンプルを開き,コードを変えて試せます。

編集する

サンプルを書き換えるか,自分の JAL ファイルを開く

実行する

実行ボタンを押し,コンソールで出力を確認する

動きを追う

ブレークポイントで止め,スタックとローカル変数を見る

Tooling

手元の開発環境で使う

手元の JVM で実行する場合は,jalc でクラスファイルや JAR を生成できます。 IntelliJ IDEA 用の Javasm と,Gradle のビルドに組み込むプラグインもあります。