More Related Content
Similar to Java 7 invokedynamic の概要
Similar to Java 7 invokedynamic の概要 (7)
More from Taku Miyakawa (17)
Java 7 invokedynamic の概要
- 2. 1
発表者
• 名前: 宮川 拓
• 職業: SI 屋で Hadooper
• オレオレ JVM 言語 Kink を開発中
– Its’ fun!
- 3. 2
invokedynamic とは?
• Java 6 までの JVM
= Java のための仮想マシン
• Java 7 の JVM
= Java + Java 以外の言語のための仮想マシン
• invokedynamic は Java 以外の言語のために
追加された新しいメソッド呼び出し命令
- 4. 3
論点
• Java 6 までの呼び出し命令
– JVM 命令は Java のために作られていた
• Java 以外の言語
– 既存の命令セットでは Java 以外の言語処理系が
効率的に実装できない
• invokedynamic
– 新しい命令で Java 以外の言語も効率的になる
- 6. 5
Java 6 までの呼び出し命令
• 4 種類
• Java のメソッド呼び出しはこれで全部 OK
invokestatic static メソッドを呼び出す
invokespecial コンストラクタ、 private メソッド等を呼び出す
invokevirtual クラスに属するメソッドを呼び出す (非 private)
invokeinterface インタフェースに属するメソッドを呼び出す
- 7. 6
invokestatic
• static メソッドの呼び出し → invokestatic
StringUtils.rjust("VOXXX", 10, '.');
javac
ldc "VOXXX" // "VOXXX” をスタックに積む
bipush 10 // 10 をスタックに積む
bipush 46 // '.' = 46 をスタックに積む
invokestatic StringUtils#rjust(String,int,char):String
- 11. 10
invokevirtual
• とある GUI ツールキットのクラス階層
Widget
Rect getRect()
Button
void push()
CheckBox OKButton
void push() void push()
boolean isPushed()
- 14. 13
invokeinterface
• 再び GUI ツールキットのクラス階層
intf Movable intf Resizable
void move(Point) void resize(Size)
class Icon class Frame
void move(Point) void resize(Size)
void move(Point)
- 17. 16
Java 6 までの呼び出し命令 (rep)
• 4 つの呼び出し命令で Java のメソッド呼び出
しをカバー
• Java に特化した仕組み
– メソッドが再定義されることはない
– 単一継承
– 名前と型の組み合わせによるメソッドの特定
– レシーバのクラスによる単一ディスパッチ
- 19. 18
古い革袋と新しい酒
Scheme
JS Python
Groovy Ruby
Scala
Java Java
JVM JVM
むかし 最近
- 20. 19
古い革袋と新しい酒
• JVM は Java のために作られたので、それ以外
の言語を動かすのには工夫が必要
• 例: Ruby ではメソッドが再定義できるので、既
存の呼び出し命令で直接呼び出せない
• 他にも
– method-missing
– 多重継承
– mix-in
- 22. 21
本当はこうしたい!
array.join
バイトコード
生成
CAFE 0000 bang! def join
3939 5151 ...
...... ...
余計な処理がなく、JIT コンパイラに
よる最適化が掛けやすくなる
- 29. 28
MethodHandle
• MethodHandle は型付き関数ポインタ
• 決まった型・数の引数をスタックから取り、結
果をスタックに置く処理を指し示す
プリミティブな MethodHandle の作成
Lookup#findVirtual • インスタンスメソッドを呼び出す
MH
Lookup#findConstructor • インスタンスを生成する MH
Lookup#findGetter • フィールドの値を返す MH
MethodHandles#constant • 定数値を返す MH
- 30. 29
MethodHandle
• MethodHandle は合成したり、引数の順序を
入れ替えたり、部分適用したりして新しい
MethodHandle を生成できる
複合的な MethodHandle の作成
MethodHandles • (if test then target else fallback) を行う
#guardWithTest MH
MethodHandles • 本処理の戻り値に後処理を加える MH
#filterReturnValue
MethodHandle • 先頭の引数の値を固定した MH
#bindTo
- 31. 30
CallSite
• ついで CallSite
初回実行時に invokedynamic
呼び出し
bootstrap <<create>>
CallSite
メソッド
任意の MH の Method bang! 対象の
処理 再登録 Handle 処理
- 32. 31
CallSite
• 1 つの invokedynamic 命令に紐付いて「呼び
出し元」を表す
• MethodHandle の参照を保持する
CallSite の具象クラス
ConstantCallSite • MH が書き換えられない
• private final MethodHandle mh
MutableCallSite • MH が書き換えられる
• private MethodHandle mh
VolatileCallSite • MH が書き換えられる
• private volatile MethodHandle mh
- 33. 32
bootstrap メソッド
• 最後に bootstrap メソッド
初回実行時に invokedynamic
呼び出し
bootstrap <<create>>
CallSite
メソッド
任意の MH の Method bang! 対象の
処理 再登録 Handle 処理
- 34. 33
bootstrap メソッド
• 各 invokedynamic 命令は bootstrap という
static メソッドへの参照を持っている
• invokedynamic 命令が最初に実行される時に
bootstrap メソッドが呼ばれて
– 命令に CallSite オブジェクトを紐付ける
– MethodHandle の初期値を CallSite に紐付ける
- 35. 34
bootstrap メソッド
• 例: 戻り値の型が int の場合、強制的に値を
42 にする
static CallSite bsm(Lookup lu, String name, MethodType mt)
throws Exception {
MethodType vmt = mt.dropParameterTypes(0, 1);
MethodHandle vmh = lu.findVirtual(mt.parameterType(0), name, vmt);
if (vmt.returnType() == int.class)
return new ConstantCallSite(filterReturnValue(vmh,
dropArguments(constant(int.class, 42), 0, int.class)));
else
return new ConstantCallSite(vmh);
}
- 36. 35
bootstrap メソッド
• 例: 「メソッド名」を文字列として戻す
– indy での「メソッド名」は bootstrap に渡す引数に
過ぎない
static CallSite bsm(Lookup lu, String name, MethodType mt) {
return new ConstantCallSite(dropArguments(
constant(String.class, name), 0, mt.parameterType(0)));
}
MethodType が引数なし
戻り値 String でないとエラー
- 37. 36
invokedynamic (rep)
• bootstrap メソッドにより、命令に紐付く処理を
言語処理系独自のやり方で選択できる
• CallSite に新しい MethodHandle を登録するこ
とにより、命令に紐付く処理を実行時に変更
できる
• これらの仕組みを JVM のレベルでサポートす
るため、賢く使うと効率的な言語処理系が実
装できる
- 39. 38
参考
• Da Vinci Machine Project (mlvm)
– http://openjdk.java.net/projects/mlvm/
• JSR 292 Cookbook
– http://cr.openjdk.java.net/~jrose/pres/200906-Cookbook.htm
• John Rose’ weblog at Oracle: dynamic invocation in the VM
– https://blogs.oracle.com/jrose/entry/dynamic_invocation_in_the_vm
• Optimizing invokedynamic
– http://dl.acm.org/citation.cfm?id=1852763
• HotSpot Internals for OpenJDK: CallingSequences
– https://wikis.oracle.com/display/HotSpotInternals/CallingSequences