きしださんに教えていただいた、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コンパイルさせることができました。