PR

InvokeDynamic

 InvokeDynamicは前述したように、今まで動的型付け言語側で行っていたコールすべきメソッドの特定を容易にすることと、JVMの最適化を受けられるようにすることを狙っています。

 そのために3つの道具を使用します。

 bootstrapはメソッド、CallSiteとMethodHandleはjava.lang.invokeパッケージで定義されているクラスです。これらの関係を図示したのが、図2です。

図2●InvokeDyanamicの道具立て
図2●InvokeDyanamicの道具立て

 CallSiteクラスはコールするターゲットのメソッドの情報を保持するクラスです。実際のメソッドへの参照はMethodHandleクラスが保持します。

 これらCallSiteオブジェクトとMethodHandleオブジェクトは、ターゲットメソッドを初めて実行する時に生成されます。このオブジェクト生成を行っているのがbootstrapです。

 では、MethodHandleクラスから見ていきましょう。

 MethodHandleクラスは前述したようにターゲットメソッドへの型付きの参照を保持するクラスです。MethodHandleクラスはinvokeなどのメソッドを定義しており、ターゲットメソッドを実行することが可能です。

 MethodHandleクラスが対応するターゲットメソッドを検索し、MethodHandleオブジェクトを生成するのがMethodHandles.Lookupクラスです。

 MethodHandles.LookupクラスにはfindVirtualメソッドやfindConstructorメソッドなどが定義されており、レシーバの型、メソッド名、引数と戻り値の型を指定すれば、MethodHandleオブジェクトを返します。

 引数と戻り値の型を表しているのが、MethodTypeクラスです。

 CallSiteクラスは、このMethodHandleを保持するクラスです。CallSiteクラスはアブストラクトクラスであり、コンクリートクラスとして次の3つのクラスが提供されています。

 ConstantCallSiteクラスはMethodHandleオブジェクトを変更できないCallSiteです。MutbleCallSiteクラスとVolatileCallSiteクラスはMethodHandleオブジェクトを変更することができます。この2つのクラスはMethodHandleオブジェクトの参照をvolatileで保持しているかどうかが違うだけです。

 そして、bootstrapがCallSiteオブジェクトを生成するためのstaticなメソッドです。メソッド名はbootstrapでなくても構わないのですが、引数の型はMethodHaldes.Lookupクラス、Stringクラス、MethodTypeクラスの順になります。第2引数の文字列がメソッド名、第3引数のMethodTypeクラスがメソッドの引数と戻り値の型を表します。そして、戻り値の型がCallSiteクラスになります。

 ターゲットメソッドの初回実行時にbootstrapをコールしてCallSiteオブジェクトを生成し、生成したCallSiteオブジェクトを使用してターゲットメソッドを実行します。2度目のターゲットメソッドの実行からは、CallSiteオブジェクトが既に存在するので、直接CallSiteオブジェクトを使用してターゲットメソッドを実行します。

 しかも、CallSiteクラス、MethodHandleクラスともJVMの仕組みとしてなっているため、JVMの最適化を適用しやすくなっています。

 また、興味深いことにMethodHandleオブジェクトを合成して、新しいMethodHandleオブジェクトを生成することも可能です。

 ユーティリティクラスのMethodHandlesクラスにはMethodHaldeオブジェクトの合成用のメソッドが複数定義されています。例えば、filterReturnValueメソッドは処理の後に、追加の処理を付け加えることができます。また、条件によって処理を切り替えることができるguardWithTestメソッドなどが定義されています。

 このようなメソッドを利用することで、複数の処理をまとめることができ、さらに効率よくメソッドコールを行うことができるようになります。