今月紹介する機能は、Javaのためではない機能であるInvokeDynamicです。

 もちろん、Javaに関係しない機能というのは、長いJavaの歴史の中でも初めてです。その背景にあるのが、JVM上で動作する言語の活況です。

 JVM上で動作する言語には、JRubyやGroovyなど動的型付けの言語が多くあります。しかし、Javaは静的型付け言語であるため、動的型付けを効率的に実装できないという問題がありました。それを解決するのが、今回紹介するInvokeDynamicです。

 なお、今回はいち早くInvokeDynamicへの対応を進めているJRubyを使用して検証を行っていきます。JRubyは原稿執筆時点での最新である1.7.0.preview1を使用しました。

InvokeDynamic導入の理由

 InvokeDynamicはJava VMに追加された新しいバイトコードと、その処理の仕組みを総称する呼び方です。バイトコードだけを示す場合、invokedyamicと表記されます。

 では、なぜ新しいバイトコードが必要なのでしょうか。簡単な例で考えてみましょう。リスト1にRubyで書いた関数の例を示します。

リスト1●Rubyで記述した関数add
def add(x, y)
  x + y
end

 関数addは引数xとyを足し合わせた値を返す関数です。しかし、xとyの型はわかりません。型が確定するのは、実行時です。

 例えば、次の例ではどうでしょうか。

リスト2●add関数をコールする
print add "Hello", "World!" # "Hello, World!"が出力
print "\n"
print add 10, 20 # 30が出力

 リスト2の1行目ではadd関数の引数の型は文字列になり、3行目では整数になっています。このように、実行時に、そのコンテキストによって型が決定するわけです。

 しかし、このようなことは静的型付け言語であるJavaではありえません。型はソースレベルで必ず決まっているはずです。では、Javaのような静的型付け言語で、動的型付け言語を実装する場合はどうするのでしょうか。

 実行時にならないと型が決定しない関数は取りうる型を補完して関数をオーバーロードしておきます。例えば、先ほどのadd関数では、引数が整数型、浮動小数点数、文字列、Objectクラスなどの場合をオーバーロードしておきます。

 そして、これらの関数の中から、実行時に引数の型によってコールすべき関数を検索し、コールします。とはいっても、毎回メソッドを検索するのでは効率が悪いため、メソッドをキャッシュするなどの効率化を図っています。

 問題は必ず検索のための処理が入るということです。この処理があるため、JVMの最適化が働きにくくなってしまいます。例えば、高速化に有効なメソッドのインライン展開などは行われなくなってしまいます。

 そこで、動的型付け言語でも、より効率的にメソッドコールを行えるように導入されたのが、InvokeDynamicです。