[JRockit] JRockit R28 issue with exact profiling and generics

原文はこちら。
https://blogs.oracle.com/buck/entry/jrockit_r28_issue_with_exact

JRockit R28をお使いの方の中には、Javaのgenerics機能を使用するメソッドに対し、Mission Controlでのexact profilingを使用すると、問題が起こることをご存知の方がいらっしゃるかもしれません。その問題とは、こうしたメソッドのInvocationカウンタが応答しない、つまり、各メソッドを呼び出すと、対応するコールカウントをインクリメントすることができない、というものです。

R28での正確なメソッド・プロファイリングのために、我々はApacheのByte Code Engineering Library (BCEL)で、元々のバイトコードインスツルメンテーション・ソリューションを置き換えました。BCELがすでにJAXPの内部コンポーネントとしてJDKに含まれているため、BCELを使うと、よりきれいなコード生成パイプラインができました。

ところが、JDKに含まれるBCELのバージョンは非常に安定しており、JAXPが必要とする非常に狭いユースケースに対し正常に動作するのに対し、Mission Control Consoleのプロファイリングツールが必要とするような状況、つまりこのBCELを使い任意のコードに対して測定する場合には問題があったのです。

これらの課題の一つは、Javaのgenericsを完全にサポートするようにBCELで実装されていなかった、ということでした。具体的には、genericなコードを持つメソッドを測定すると、LocalVariableTable(LVT)属性とLocalVariableTypeTable(LVTT)属性間の不整合を持つバイトコードを生成する可能性がありました(詳細は以下のドキュメントを参照して下さい)。
The class File Format
http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 
ありがたいことに、この問題はBCELプロジェクトが(開発ブランチで)発見し、修正してくれました。
Bug  39695 - java.lang.ClassFormatError: LVTT entry for 'local' in class  file org/shiftone/jrat/test/dummy/CrashTestDummy does not match any LVT  entry
https://issues.apache.org/bugzilla/show_bug.cgi?id=39695
ただ不幸にも、JDKに含まれるBCELにはこの修正が含まれていません。そのため、JRockitがBCELを使ってこれらのメソッドを計測しようとすると、元の測定されていないメソッドのバージョンが残ったまま、新しいメソッドのバイトコードは無効になり、その後のバイトコード検証に失敗します。

JRockitにコードを追加すればBCELの問題を回避できると簡単に考えましたが、JDK自体に含まれるBCELのバージョンを修正するのが王道のように思えました。ただ残念ながら、バグ39695の修正は、最近のJDKに含まれているものよりもずっと新しいBCELのバージョンをベースとしていたので、正常に動作するよう、他の多くのコードを移植する必要がありました。
JDK-8003147: port fix for BCEL bug 39695 to our copy bundled as part of jaxp
https://bugs.openjdk.java.net/browse/JDK-8003147
BCELの修正やその他の必要なコードは、5u45、6u60および7u40に入れました。なお、Java 5についてご注意いただきたいのですが、修正はCPUリリースにしか組み込むことはできなかったということです。なぜならもはやJava 5に対するCPUリリース以外での修正を提供していないからです。これはつまり、この修正を施したJRockitのバージョンは、Javaのメジャーバージョンによって変わる、ということです。具体的に言うと、Java 5はR28.2.7、Java 6はR28.2.9です。LVT/LVTTは通常はデバッグビルドにのみ含まれますので、-gフラグなしで影響を受けたクラスの再コンパイルは、以前のリリースをお使いの方にとって実行可能な回避策でもあります。

それほど多くの方にこの問題が影響しないことを願うばかりです。「JRockit: The Definitive Guide」に詳しく記載があるように、(Flight Recorderが提供する類の)サンプリングベースのプロファイリングは、ほとんどの場合はexact profilingよりもよい選択です。
Oracle JRockit: The Definitive Guide
http://www.packtpub.com/oracle-jrockit-definitive-guide/book 
しかし、この話は別の理由で興味深いものです。すなわち、JDKに含まれる(公式に文書化されていない)内部クラスに依存することがほとんどの場合は常に間違った考えであるか、を示す好例です(*1)。たとえ痛い目に遭うとわかっていても。

(*1) 今後のJavaクラスライブラリのモジュール化によって、内部JDKクラスを外部で使用できないようになることを期待しています。(その機能が既にあったなら)もしかしたらここで役立ったかもしれません。

0 件のコメント:

コメントを投稿