Valhallaの話

この記事はJVM Advent Calendar 2014 - Qiitaの22日目(?)の記事です.
9日目の記事かもしれません.

さて,今日はProject Valhalla上の特殊化のバイトコードレベルでの実装とかの話を書こうかと思っていました.

こうしたプロジェクトの概略はState of the XXXといったドキュメントでまとめられています.
特殊化(Specialization)も同様に「State of the Specialization」というドキュメントでプロジェクトリードのBrian Goetz氏がまとめています.
これに基づいて書いていく予定だったのですが,なんとつい先日*1にドキュメントがアップデートされてしまいました.
まだ深く読み込めていないので,ここではガッツリ紹介するというよりも,いくつか参考になるドキュメントと,実装がどうなりそうなのかを軽く紹介しようかと思います.

参考になるドキュメント

Project Valhalla(プロジェクトページ)
プロジェクトのページです.基本的に他のドキュメントはここらへんから辿れるはずです.

メーリングリスト
Project Valhallaのメーリスです.登録しておくと良いかも.
アーカイブも見れます.

State of the Specialization
特殊化のドキュメントです.
12/20にアップデートがありました.
過去のやつはこちらから.

Overview of specialized classfile format
特殊化におけるクラスファイルのフォーマットです.

Class Dynamic
クラスの動的生成,ローディング等をJVM上でサポートするという話

一ヶ月ぐらいは楽しめそうな分量のドキュメントです!!

特殊化の実装

特殊化では型変数を実際の型で置き換えなければいけません.
ですが,Javaのクラスファイルではイレージャによって型変数の情報が取り除かれてしまっています.
これでは,置き換えるべき型がどれなのかわかりません.
そのため,型の情報に加えて型変数名の情報もバイトコード上に残します.

例えば,以下のBoxというクラスを考えます.

public class Box<T> {
    private T t;

    public Box(T t) {
       this.t = t;
    }
}

すると,イレージャによってTはjava.lang.Objectに置き換えられて,次のようなコードが生成されます.

public class Box {
    private Object t;

    public Box(Object t) {
       this.t = t;
    }
}

特殊化に対応して,型情報の残すと次のようなコードを生成します.

public class Box {
    private Object*T t;

    public Box(Object*T t) {
       this.t = t;
    }
}

ちなみに*Tはイメージです.実際にはクラスファイルに型変数情報のテーブル(TypeVariablesMap)が追加されて,それぞれが対応付けられます.

Tがintの場合には,インスタンス生成時にObject*Tがintで置き換えられます.

続いてメソッド内の実装をバイトコードレベルで見ていきます.
特殊化に対応していないコードは次のようになっています.

   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aload_1         // 引数を取ってくる
   6:   putfield    #2; //Field t:Ljava/lang/Object;
   9:   return

aload_XXというのはローカル変数からオブジェクトを取ってきてスタックに積むということを意味しています.
intを取ってくる場合はiloadという命令を使わなければいけません.
他のプリミティブ型についてもそれぞれ命令がご丁寧に用意されています.

そこで,バイトコードに対しても型変数の情報を残します.
インスタンス生成時にTがintの時にはiloadを使ったコードに変換するなどして,動的にコードを生成します.

   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   aload_0
   5:   aload_1*T
   6:   putfield    #2; //Field t:Ljava/lang/Object*T;
   9:   return

この情報はバイトコードの変換テーブル(BytecodeMapping)として扱われて,クラスファイルに書かれます.

バイトコード&クラスファイル楽しい!!!✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌

*1:2日前