| benf.org : other : cfr : Java 7 Switch On String |
Since this is just about usable now, I thought I'd try it with some of the java 7 features. I had wondered how switch on string worked. I was just about right, (like so much in java-land, it's all syntactic sugar) but it still leaves me feeling rather sad.
(This isn't a secret - the original proposal is here, but, like I mention elsewhere, reverse engineering this stuff is fun!)
int test0(String s) {
switch (s) {
default:
System.out.println("Test");
break;
case "BB": // BB and Aa have the same hashcode.
return 12;
case "Aa":
case "FRED":
return 13;
}
System.out.println("Here");
return 0;
}
With the nostringswitch parameter, we can tell CFR not to re-sugar string switches. This lets us see the code that javac has created - effectively it's creating a hardcoded hashtable with chaining for the first switch...
public int test0(String s)
{
unnamed_local_s_2 = s;
unnamed_local_s_3 = -1;
switch (unnamed_local_s_2.hashCode()) {
case 2112: {
if (unnamed_local_s_2.equals("Aa")) {
unnamed_local_s_3 = 2;
break;
}
if (!(unnamed_local_s_2.equals("BB"))) break;
unnamed_local_s_3 = 1;
break;
}
case 2166379: {
if (!(unnamed_local_s_2.equals("FRED"))) break;
unnamed_local_s_3 = 3;
}
}
switch (unnamed_local_s_3) {
default: {
System.out.println("Test");
break;
}
case 1: {
return 12;
}
case 2: case 3: {
return 13;
}
}
System.out.println("Here");
return 0;
}
It relies on (quite reasonable) the fact that since the buggy early version of hashcode was fixed, java's String hashcode has an explicit algorithm, which is fair enough. But it needs the two pass switch to handle fallthrough and collisions... :P
If you don't specify --nostringswitch, as of 0_6, cfr will resugar the switch, and output the following
public int test0(String s)
{
switch (s) {
default: {
System.out.println("Test");
break;
}
case "BB": {
return 12;
}
case "Aa": case "FRED": {
return 13;
}
}
System.out.println("Here");
return 0;
}
For interests sake, here is javap's output
public int test0(java.lang.String);
Code:
0: aload_1
1: astore_2
2: iconst_m1
3: istore_3
4: aload_2
5: invokevirtual #2 // Method java/lang/String.hashCode:()I
8: lookupswitch { // 2
2112: 36
2166379: 64
default: 75
}
36: aload_2
37: ldc #3 // String Aa
39: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
42: ifeq 50
45: iconst_2
46: istore_3
47: goto 75
50: aload_2
51: ldc #5 // String BB
53: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
56: ifeq 75
59: iconst_1
60: istore_3
61: goto 75
64: aload_2
65: ldc #6 // String FRED
67: invokevirtual #4 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
70: ifeq 75
73: iconst_3
74: istore_3
75: iload_3
76: tableswitch { // 1 to 3
1: 115
2: 118
3: 118
default: 104
}
104: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
107: ldc #8 // String Test
109: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
112: goto 121
115: bipush 12
117: ireturn
118: bipush 13
120: ireturn
121: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
124: ldc #10 // String Here
126: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
129: iconst_0
130: ireturn
| Last updated 02/2013 |