emc v0.0.2をリリースしました

以下で書いたJVMのメモリ設定をアプリケーションのjarファイルから自動で計算してくれるツールです。 progret.hatenadiary.com

v0.0.2をリリースしました。 リリースされた機能は以下の一つです。

  • [experimental] ラムダ式をクラスファイル数にカウントする

ラムダ式をクラスファイル数にカウントする理由としては ラムダ式を実行した場合、クラスの定義がランタイムに行われるからです。

この機能を実装するために、クラスファイルのパーサーをforkして 必要な機能に対応したのが以下のリポジトリにあるモジュールです。

github.com

インストール方法

# 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は読んでみると面白いですね。

終わり。