dalvik のパック スイッチ オペコードとスパース スイッチ オペコードの違いを知りたいです。例を提供できる場合はお願いします。グーグルが提供する説明は私には不明確です。
ありがとう。
Java のや と同等packed-switch
であるかのように聞こえます。tableswitch
sparse-switch
lookupswitch
は、のpacked-switch
形式でインデックス付けされた単純なジャンプ テーブルを使用しますlow + n
。ここで、 はラベルのlow
中で最も低いテスト値であり、は への入力です。各インデックスの値は、それぞれのバイトコード オフセットを表します。正しいジャンプ アドレスを見つけることは、一定時間の操作です。case
n
switch
case
は、キーと値のペアのソートされたsparse-switch
リストを使用します。各キーはcase
ラベルからのテスト値であり、値はジャンプ オフセットです。a の正しいジャンプ ターゲットを見つけるにはlookupswitch
、キーのバイナリ検索が必要なため、対数時間演算になります。
どちらを使用するかはコンパイラが選択します。キーがクラスター化または密接にパックされる傾向がある場合は、 a packed-switch
(Java 用語では a tableswitch
) を効率的に発行できます。ただし、キーがsparseで、値の範囲 ( ) が大きい場合、対応するラベルhigh - low + 1
があるかどうかに関係なく、その範囲内のすべての値がジャンプ テーブルに存在する必要があるため、ジャンプ テーブルを使用するには大きなバイトコード ブロックが必要になります。case
. これらのシナリオでは、コンパイラはsparse-switch
( lookupswitch
) を出力します。
興味深いことに、Dalvik のエンジニアは、これらのオペコードが使用されるキーの配布を説明する方法で名前を付けることを選択しましたが、Java のエンジニアは、バイトコード オペランドが似ている概念的なデータ構造を説明する名前を選択しました。
いくつかの例を見てみましょう。tableswitch
(そして、Dalvik に変換すると、packed-switch
)を生成する次の Java コードを考えてみましょう。
static String packedSwitch(final int n) {
switch (n) {
case 5:
return "Five";
case 3:
return "Three";
case 1:
return "One";
default:
return "Other";
}
}
概念的には、packed-switch
オペコードのペイロードは次のようになります。
ご覧のとおり、かなりコンパクトです。5 つのスロットのうち 3 つが実際のターゲットを指しcase
、残りの 2 つがdefault
ターゲットにジャンプします。しかし、テスト値がもっと分散していたらどうでしょうか?
static String sparseSwitch(final int n) {
switch (n) {
case 500:
return "Five Hundred";
case 300:
return "Three Hundred";
case 100:
return "One Hundred";
default:
return "Other";
}
}
コンパイラがこれを として出力しようとするpacked-switch
と、ペイロードは次のようになります。
case
数百のスロットのうち 3 つだけが元のコードのラベルを実際に指していることに注意してください。残りはジャンプ テーブルを埋めるためだけに存在します。あまりスペース効率がよくありませんね。そのため、コンパイラはsparse-switch
、この特定の例でははるかにコンパクトなバイトコード フットプリントを持つ を出力します。
それははるかに合理的だと思いませんか?ただし、欠点は、入力に基づいてジャンプ先のインデックスを正確に知る代わりに、一致するテスト値が見つかるまでテーブルでバイナリ検索を実行する必要があることです。スイッチが大きいほど、パフォーマンスへの影響は大きくなりますが、効果は対数曲線になります。