1 4 package gnu.bytecode; 5 6 7 8 public class SwitchState 9 { 10 11 int minValue; 12 13 int maxValue; 14 15 int numCases; 16 17 int[] values; 18 19 Label[] labels; 20 21 Label defaultLabel; 22 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(); 36 typeState = code.saveStackTypeState(false); 38 39 code.fixupChain(cases_label, switch_label); 40 41 numCases = 0; 42 } 43 44 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 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 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 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); 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); 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 |