きしださんに教えていただいた、Graalについての非常によい入門記事があります。
Understanding How Graal Works - a Java JIT Compiler Written in Java
Graalの上のTruffleでのRuby実装であるTruffleRubyを開発しているChris Seatonさんのブログです。この記事の内容に沿って、Graalの理解を深めていきます。
Graalのセットアップはこちらを参考にしてください。
JVMCIを通じてGraalにJITコンパイルさせる
Graalは新しいJITコンパイラです。今のC1/C2コンパイラのC2を置き換えるものです。Java 9でGraalにJITコンパイルさせることができますが、その際にJVMのリビルドは必要ありません。Java 9からJVMCIがあるからです。
JVMCIは"JEP 243: Java-Level JVM Compiler Interface"のことで、Java 9から導入されています。これを使うと、たとえば今回のようにJITコンパイラをリビルドせずに実行時に入れ替えたりできます。起動オプションで指定します。Javaエージェントと同じような使用方法です。
まずは復習がてら、C1/C2で動作させ、JITコンパイルされたメソッドを出力します。まずは対象クラスです。単にメインメソッドで無限ループして、固定数値の加算をするだけです。
class Demo { public static void main(String[] args) { while (true) { workload(14, 2); } } private static int workload(int a, int b) { return a + b; } }
JITコンパイルされたメソッドを指定するのは-XX:+PrintCompilation、すべてのメソッドではなく特定のメソッド(複数指定可)のみ出力するのは-XX:CompileOnly=xxxです。
$ java \
-XX:+PrintCompilation \
-XX:CompileOnly=Demo::workload \
-XX:CompileCommand=quiet \
Demo
...
121 1 3 Demo::workload (4 bytes)
121 2 1 Demo::workload (4 bytes)
121 1 3 Demo::workload (4 bytes) made not entrant
...
121はタイムスタンプ(ミリ秒)、1/2がコンパイルID、3/1は階層型コンパイルの各層です。階層型コンパイルについては本題でないので、また別の機会に。made not entrantは脱最適化されたということです。
ではJVMCIを有効にして、GraalにJITコンパイルさせてみましょう。EnableJVMCIがまだexperimentalなので、-XX:+UnlockExperimentalVMOptionsをつけます。ないとVM option 'EnableJVMCI' is experimental and must be enabled via -XX:+UnlockExperimentalVMOptions.と言われます。
これだけではGraalがJITコンパイラとして使われず、通常のJITコンパイラが使われます。JVMCIを通じてJITコンパイルするため-XX:+UseJVMCICompilerをつけます。階層型コンパイルのままだとC1コンパイラが残っており、C1のコンパイルも出てくるので階層型コンパイルを無効にします(-XX:-TieredCompilation)。
$ java \
--module-path=graal/sdk/mxbuild/modules/org.graalvm.graal_sdk.jar:graal/truffle/mxbuild/modules/com.oracle.truffle.truffle_api.jar \
--upgrade-module-path=graal/compiler/mxbuild/modules/jdk.internal.vm.compiler.jar \
-XX:+UnlockExperimentalVMOptions \
-XX:+EnableJVMCI \
-XX:+UseJVMCICompiler \
-XX:-TieredCompilation \
-XX:+PrintCompilation \
-XX:CompileOnly=Demo::workload \
-XX:CompileCommand=quiet \
Demo
...
140 22 n java.lang.invoke.MethodHandle::linkToInterface(LLL)I (native) (static)
383 23 n java.lang.invoke.MethodHandle::linkToStatic(LLIIL)I (native) (static)
384 24 n java.lang.invoke.MethodHandle::linkToSpecial(LLLL)V (native) (static)
526 25 Demo::workload (4 bytes)
...
なお、-upgrade-module-pathはシステムモジュールを置き換えるオプションです。JVMCI関連のモジュールをgraalでビルドしたものに置き換えています。
さて、出力が変わりました。やたらMethodHandleのコンパイルが出てきますね。まだ詳しいことはわかりませんが、GraalにJITコンパイルさせることができました。