1

次のシグネチャを持つメソッドがあるとします。

public int indexOf(byte[] bytes, byte toFind, int offset, int length) {
  ...
}

toFindこのメソッドは、[offset, offset+length) in の範囲内のバイトを探すような単純なことを行いますbytes。のオフセットと長さが有効かどうかを事前に確認したいbytes。つまり、そのオフセットとオフセット + 長さはバイト単位になります。

明示的なチェックは次のようになります。

if (offset < 0 || offset > bytes.length - length) {
  throw ...;  // bad santa!
}

代わりに「ダミー」配列アクセスを実行することで、これをより安価に実行できるようです (発行されたバイトコード、およびおそらく実行時のパフォーマンスの点で)。

public int indexOf(byte[] bytes, byte toFind, int offset, int length) {
  int dummy = bytes[offset] + bytes[offset + length - 1];
  ...
}

できればint dummyandを取り除くか、そのコストを削減したいと思います。+おそらく、このようbytes[offset];な式には通常副作用がなく、無意味であるためです (ただし、この場合はそうではありません)。ダミーの int を使用すると、抑制しなければならないコンパイラ警告も発生します。

最小量のバイトコードで変更を行う方法に関する提案 (実行時のパフォーマンスもここで重要ですが、ほとんどのソリューションは未使用部分が削除されるのと同じように最適化されていると思います)。

4

4 に答える 4

2

これはどう ?

if ((bytes[offset] | bytes[offset+length-1])==0) { }
于 2013-01-03T23:11:37.263 に答える
1

実行するだけで、最も安価な方法であるbytes[offset]ことを願っています。bytes[offset + length - 1]JVM バイトコードでの最短の方法は、これらの式を実行してオペランド スタックに残すことです。

ただし、Java ではできません。また、有効な Java コマンドではないため、pop2命令 (または 2 つのpop命令)も使用できません。bytes[something]潜在的に最善の方法が 3 つあります。

  1. のようなメソッド呼び出しを使用しますint java.lang.Math.max(int, int)invokestaticこれにより、1 つの 3 バイト命令と 1 つの 1バイト命令が追加されますpop。したがって、これは 4 バイトのオーバーヘッドです。int2 つの引数とvoid結果を持つ静的ダミー メソッドを作成すると、1 バイト節約できます。インテリジェントな JVM オプティマイザーは、副作用がなく、命令ごとに結果を破棄するため、おそらくこのコードを 1 つのpop2命令に削減します。ただし、これがホットスポットに当てはまるかどうかはわかりません。Math.max(...)pop
  2. ローカル変数に割り当てます。1 つの割り当ては 1 つのistore命令を意味します。5 つのパラメーター (thisメソッドが静的ではないため、 を含む) がある場合は、istore1 バイトではなく一般的な 2 バイト バージョンを使用しますistore_<n>({0, 1, 2, 3} の n の場合)。パラメーターが 3 つ以下の場合は、ダミー変数のスコープを縮小することでおそらく何かを節約できます。
  3. それを比較して (=> ブール値を生成)、空のブランチを使用しますif ((bytes[offset] == bytes[offset+length-1])) { }。この場合、追加のメソッド (max や pop2 など) や追加のローカル変数 (ローカル変数テーブルを拡大する) は必要ありません。

これ以上のオプティマイザを使用せず、使用する変数を減らすためにメソッド シグネチャを変更しない場合は、おそらく 3 番目の方法が勝者となります。私の簡単なテストでは、命令に 16 バイトしか必要とせず (他のいくつかの実装も同等ですが、それ以上ではありません)、ローカル変数テーブルまたは定数プールにはそれ以上は必要ありません。手動のバイトコード最適化または Proguard によって、おそらく数バイトを節約できます。ただし、注意してください。Proguard は最適化しすぎて、配列へのアクセスを削除する可能性があります。(確かではありませんが、一部の NullPointerExceptions が削除される可能性があるとドキュメントで主張しています。)

https://gist.github.com/4523924を参照してください。

于 2013-01-13T12:49:49.707 に答える
0

バイトコードの長さについてはわかりませんが、どうですか:

bytes[offset] |= bytes[offset];
bytes[offset + length - 1] |= bytes[offset + length - 1];
于 2013-01-03T23:07:35.623 に答える