KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > bytecode > SwitchState


1 // Copyright (c) 1998, 2004 Per M.A. Bothner.
2
// This is free software; for terms and warranty disclaimer see ./COPYING.
3

4 package gnu.bytecode;
5
6 /** Maintains the state for generating a switch statement. */
7
8 public class SwitchState
9 {
10   /** The smallest case value, so far. */
11   int minValue;
12   /** The largest case value, so far. */
13   int maxValue;
14   /** The number of cases (not including the default case). */
15   int numCases;
16   /** The case values, in numerical order (in values[0..numCases-1]). */
17   int[] values;
18   /** The case locations, in the same order as values. */
19   Label[] labels;
20   /** The location to jump to if none of the cases match. */
21   Label defaultLabel;
22   /* Location of the actual switch instruction. */
23   Label switch_label;
24   Label cases_label;
25   Type[] typeState;
26
27   public int getMaxValue() { return maxValue; }
28
29   public SwitchState(CodeAttr code)
30   {
31     switch_label = new Label(code);
32     cases_label = new Label(code);
33
34     code.popType(); // pop switch value
35

36     // Save stack types (except top int) into typeState
37
typeState = code.saveStackTypeState(false);
38
39     code.fixupChain(cases_label, switch_label);
40
41     numCases = 0;
42   }
43
44   /** Emit a new case, for the given value, whose label is here. */
45   public boolean addCase(int value, CodeAttr code)
46   {
47     Label label = new Label(code);
48     boolean ok = addCase (value, label, code);
49     label.define(code);
50     code.restoreStackTypeState(typeState);
51     return ok;
52   }
53
54   public void addDefault(CodeAttr code)
55   {
56     Label label = new Label(code);
57     label.define(code);
58     addDefault(label, code);
59   }
60
61   public void addDefault(Label label, CodeAttr code)
62   {
63     defaultLabel = label;
64     code.restoreStackTypeState(typeState);
65   }
66
67   /** Add a new case.
68    * @param value the case value to match against at run-time
69    * @param label the location to go to if the value matches
70    * @param code the CodeAttr of the Method we are generating code for
71    * @return true on success; false if value duplicates an existing value
72    */

73   public boolean addCase(int value, Label label, CodeAttr code)
74   {
75     if (values == null)
76       {
77     values = new int[10];
78     labels = new Label[10];
79     numCases = 1;
80     minValue = maxValue = value;
81     values[0] = value;
82     labels[0] = label;
83     return true;
84       }
85     int[] old_values = values;
86     Label[] old_labels = labels;
87     if (numCases >= values.length)
88       {
89     values = new int[2 * numCases];
90     labels = new Label[2 * numCases];
91       }
92     int copyBefore;
93     if (value < minValue)
94       {
95     copyBefore = 0;
96     minValue = value;
97       }
98     else if (value > maxValue)
99       {
100     copyBefore = numCases;
101     maxValue = value;
102       }
103     else
104       {
105     // Binary search.
106
int low = 0;
107     int hi = numCases - 1;
108     copyBefore = 0;
109     while (low <= hi)
110     {
111       copyBefore = (low + hi) >> 1;
112       if (old_values[copyBefore] >= value)
113         hi = copyBefore - 1;
114       else
115         low = ++ copyBefore;
116     }
117
118     if (value == old_values[copyBefore])
119       return false;
120       }
121     int copyAfter = numCases - copyBefore;
122     System.arraycopy(old_values, copyBefore, values, copyBefore+1, copyAfter);
123     System.arraycopy(old_values, 0, values, 0, copyBefore);
124     values[copyBefore] = value;
125     System.arraycopy(old_labels, copyBefore, labels, copyBefore+1, copyAfter);
126     System.arraycopy(old_labels, 0, labels, 0, copyBefore);
127     labels[copyBefore] = label;
128     numCases++;
129     return true;
130   }
131
132   /** Handle the end of the switch statement.
133    * Assume the case value is on the stack; go to the matching case label. */

134   public void finish (CodeAttr code)
135   {
136     if (defaultLabel == null)
137       {
138     defaultLabel = new Label(code);
139     defaultLabel.define(code);
140     ClassType ex = ClassType.make("java.lang.RuntimeException");
141     code.emitNew(ex);
142     code.emitDup(ex);
143     code.emitPushString("bad case value!");
144     Type[] args = { Type.string_type };
145     Method con = ex.addMethod("<init>", Access.PUBLIC,
146                   args, Type.void_type);
147     code.emitInvokeSpecial(con);
148     code.emitThrow();
149       }
150     Label after_label = new Label(code);
151     code.fixupChain(switch_label, after_label);
152     if (numCases <= 1)
153       {
154     code.pushType(Type.int_type);
155     if (numCases == 1)
156       {
157         code.emitPushInt(minValue);
158         code.emitGotoIfEq(labels[0]);
159       }
160     else
161       {
162         code.emitPop(1);
163       }
164     code.emitGoto(defaultLabel);
165       }
166     else if (2 * numCases >= maxValue - minValue)
167       {
168     code.reserve(13 + 4 * (maxValue - minValue + 1));
169     code.fixupAdd(CodeAttr.FIXUP_SWITCH, null);
170     code.put1(170); // tableswitch
171
code.fixupAdd(CodeAttr.FIXUP_CASE, defaultLabel);
172     code.PC += 4;
173     code.put4(minValue);
174     code.put4(maxValue);
175     int index = 0;
176     for (int i = minValue; i <= maxValue; i++)
177       {
178         Label lab = values[index] == i ? labels[index++] : defaultLabel;
179         code.fixupAdd(CodeAttr.FIXUP_CASE, lab);
180         code.PC += 4;
181       }
182       }
183     else
184       {
185     code.reserve(9 + 8 * numCases);
186     code.fixupAdd(CodeAttr.FIXUP_SWITCH, null);
187     code.put1(171); // lookupswitch
188
code.fixupAdd(CodeAttr.FIXUP_CASE, defaultLabel);
189     code.PC += 4;
190     code.put4(numCases);
191     for (int index = 0; index < numCases; index++)
192       {
193         code.put4(values[index]);
194         code.fixupAdd(CodeAttr.FIXUP_CASE, labels[index]);
195         code.PC += 4;
196       }
197       }
198     code.fixupChain(after_label, cases_label);
199   }
200 }
201
Popular Tags