emc v0.0.2をリリースしました
以下で書いたJVMのメモリ設定をアプリケーションのjarファイルから自動で計算してくれるツールです。 progret.hatenadiary.com
v0.0.2をリリースしました。 リリースされた機能は以下の一つです。
- [experimental] ラムダ式をクラスファイル数にカウントする
ラムダ式をクラスファイル数にカウントする理由としては ラムダ式を実行した場合、クラスの定義がランタイムに行われるからです。
この機能を実装するために、クラスファイルのパーサーをforkして 必要な機能に対応したのが以下のリポジトリにあるモジュールです。
インストール方法
# MacOS curl -L https://github.com/wreulicke/emc/releases/download/v0.0.2/emc_0.0.2_darwin_amd64 -o /usr/local/bin/emc # Linux curl -L https://github.com/wreulicke/emc/releases/download/v0.0.2/emc_0.0.2_linux_amd64 -o /usr/local/bin/emc # Windows curl -L https://github.com/wreulicke/emc/releases/download/v0.0.2/emc_0.0.2_windows_amd64.exe -o <path-directory>/emc.exe
ラムダ式で定義されるクラスをクラスファイルから検出する方法
ラムダ式で定義されるクラスの数は
クラスファイルにはBootstrapMethodsというAttributeがあり
その中に、java/lang/invoke/LambdaMetafactory.metaFactory
というメソッドへの参照が書かれている数で検出可能です。
これ自体はそんな難しい事はありません。
大変だったのは、クラスファイルのパーサーを拡張する事でした。
それが次のDoubleとFloatの定数に関する話です。
DoubleとFloatの定数の話
少しコンスタントプールの仕様を読んでいて面白い内容があったのでここに書いておきます。 DoubleとFloatの定数がある場合、クラスファイルの構造上、どうなるかご存知でしょうか?
コンスタントプールとしてはDoubleとFloatは値としては、1枠で表現されます。 しかし、仕様上、なぜか次の枠を飛ばす事になっています。 emcはこれが原因でクラスファイルのパースに失敗するようになっていました。
クラスファイルパーサで対応した部分は以下の部分です。 go-java-class-parser/constant_pool.go at 4a96d1c7ef56592775fe2c8e0ee376a74c042ed4 · wreulicke/go-java-class-parser · GitHub
ちなみに JVM Specificationにもちゃんとこれは書かれていて 以下のように書かれています。
全ての8バイトの定数は2つのエントリを使います。LongとDoubleの定数のエントリがnにある場合、次に使えるのは n + 2のエントリです。 n + 1は有効だが使用不可だと見なされます。 振り返ってみると8バイトの定数が2つのコンスタントプールのエントリを取るのは、悪い選択でした。 と書かれています。
All 8-byte constants take up two entries in the constant_pool table of the class file. If a CONSTANT_Long_info or CONSTANT_Double_info structure is the entry at index n in the constant_pool table, then the next usable entry in the table is located at index n+2. The constant_pool index n+1 must be valid but is considered unusable. In retrospect, making 8-byte constants take two constant pool entries was a poor choice.
面白いですね。
まとめ
ラムダ式の数もクラスファイル数としてカウントする実験的機能を追加したemc v0.0.2をリリースしました。
その際、クラスファイルをパースする必要があったので、クラスファイルパーサをforkして拡張しましたが DoubleとLongの定数の仕様には驚かされました。 JVM Specificationは読んでみると面白いですね。
終わり。