2014-08-29 21 views
17

Derleme anahtarlarında JVM specification okurum ve Dize'deki anahtar ifadesinin nasıl derlendiğiyle ilgilenmeye başladım. İşte incelenen test yöntemi (JDK1.7.0_40) 'dir:Dize derlemelerini niçin iki anahtar olarak değiştirmelisiniz

static int test(String i) { 
    switch (i) { 
     case "a": return -100; 
     case "45b": return 1; 
     case "c": return 2; 
     default: return -1; 
    } 
} 
Bu yöntem dize hashCode üzerinde basit lookupswitch içine derlenmiş bekliyoruz

ancak

static int test(java.lang.String); 
Code: 
    0: aload_0 
    1: astore_1 
    2: iconst_m1 
    3: istore_2 
    4: aload_1 
    5: invokevirtual #6   // Method java/lang/String.hashCode:()I 
    8: lookupswitch { // 3 
       97: 44 
       99: 72 
      51713: 58 
      default: 83 
     } 
    44: aload_1 
    45: ldc   #7 // String a 
    47: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 
    50: ifeq   83 
    53: iconst_0 
    54: istore_2 
    55: goto   83 
    58: aload_1 
    59: ldc   #9 // String 45b 
    61: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 
    64: ifeq   83 
    67: iconst_1 
    68: istore_2 
    69: goto   83 
    72: aload_1 
    73: ldc   #10 // String c 
    75: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z 
    78: ifeq   83 
    81: iconst_2 
    82: istore_2 
    83: iload_2 
    84: tableswitch { // 0 to 2 
       0: 112 
       1: 115 
       2: 117 
      default: 119 
     } 
112: bipush  -100 
114: ireturn 
115: iconst_1 
116: ireturn 
117: iconst_2 
118: ireturn 
119: iconst_m1 
120: ireturn 

Gördüğünüz gibi aniden

, İlk arama anahtarının dallarında JVM, bunun yerine sonraki tablo için gerçek iş üreten indeksleri yapmıyor (satır 84).
Tablo düğmesi hızlı çalışmalı, bu yüzden çok fazla iş getirmeyin. Ama neyse, ek anahtar oluşturma amacı nedir?
Güncelleştirme
hashCode çakışmalarının olasılığını anlıyorum. Söylemeye çalıştığım şey, sonraki tablo anahtarı yerine, derleyici tüm gerçek işleri sonraki tablo anahtarından ilkine taşıyabilir ve sonra tüm anahtar dallarının sonuna atlamak için ifeq kullanır. Bu yüzden burada gördüğüm olası bir cevap: ilk derleyici derleyicisinde, bilinen vaka sayısına dayanarak ifeq atlama için etiketin önceden işlemeye çalıştığı, ancak bunun tek neden olduğundan emin değilim. @ericbn önerildiği gibi

Update2
, ben int ve derleyici bana düz lookupswitch verdi i ile

switch (i) { 
    case 97: return -100; 
    case 51713: return 1; 
    case 99: return 2; 
    default: return -1; 
} 

derlemeye çalıştık.

+0

Farklı String (lar) nedeniyle pigeonhole prensibi aynı hashCode sahip olabilir. Sanırım bu yüzden iki anahtar (lar) var. –

+2

Sadece bir anahtar olduğunu düşünmüyor musunuz? ikinci anahtar koşullu dönüş içindir. – HuStmpHrrr

+1

@HuStmpHrrr İkinci anahtar, görünüşte beklenmedik bir dolaylı katma katmanı sunar; tablodan bakılan atlar, "goto" hedefleri olarak ilk anahtar bloğuna direk olarak yerleştirilmiş olabilir. –

cevap

11

javac source code den alıntı:

  * The general approach used is to translate a single 
     * string switch statement into a series of two chained 
     * switch statements: the first a synthesized statement 
     * switching on the argument string's hash value and 
     * computing a string's position in the list of original 
     * case labels, if any, followed by a second switch on the 
     * computed integer value. The second switch has the same 
     * code structure as the original string switch statement 
     * except that the string case labels are replaced with 
     * positional integer constants starting at 0. 
     * 
     * The first switch statement can be thought of as an 
     * inlined map from strings to their position in the case 
     * label list. An alternate implementation would use an 
     * actual Map for this purpose, as done for enum switches. 
     * 
     * With some additional effort, it would be possible to 
     * use a single switch statement on the hash code of the 
     * argument, but care would need to be taken to preserve 
     * the proper control flow in the presence of hash 
     * collisions and other complications, such as 
     * fallthroughs. Switch statements with one or two 
     * alternatives could also be specially translated into 
     * if-then statements to omit the computation of the hash 
     * code.