1 package serp.bytecode;
2
3 import java.io.*;
4 import java.util.*;
5
6 import serp.bytecode.visitor.*;
7 import serp.util.*;
8
9 /***
10 * The <code>lookupswitch</code> instruction.
11 *
12 * @author Abe White
13 */
14 public class LookupSwitchInstruction extends JumpInstruction {
15
16 private List _matches = new LinkedList();
17 private List _cases = new LinkedList();
18
19 LookupSwitchInstruction(Code owner) {
20 super(owner, Constants.LOOKUPSWITCH);
21 }
22
23 int getLength() {
24
25
26 int length = 1;
27
28
29
30 int byteIndex = getByteIndex() + 1;
31 for (; (byteIndex % 4) != 0; byteIndex++, length++);
32
33
34 length += 8;
35
36
37 length += (8 * _matches.size());
38 return length;
39 }
40
41 public int getStackChange() {
42 return -1;
43 }
44
45 /***
46 * Synonymous with {@link #getTarget}.
47 */
48 public Instruction getDefaultTarget() {
49 return getTarget();
50 }
51
52 /***
53 * Synonymous with {@link #setTarget}.
54 */
55 public LookupSwitchInstruction setDefaultTarget(Instruction ins) {
56 return (LookupSwitchInstruction) setTarget(ins);
57 }
58
59 /***
60 * Synonymous with {@link #getOffset}.
61 */
62 public int getDefaultOffset() {
63 return getOffset();
64 }
65
66 /***
67 * Synonymous with {@link #setOffset}.
68 */
69 public LookupSwitchInstruction setDefaultOffset(int offset) {
70 setOffset(offset);
71 return this;
72 }
73
74 /***
75 * Set the match-jumppt pairs for this switch.
76 *
77 * @return this instruction, for method chaining
78 */
79 public LookupSwitchInstruction setCases(int[] matches,
80 Instruction[] targets) {
81 _matches.clear();
82 _cases.clear();
83 for (int i = 0; i < matches.length; i++)
84 _matches.add(Numbers.valueOf(matches[i]));
85 for (int i = 0; i < targets.length; i++) {
86 InstructionPtrStrategy next = new InstructionPtrStrategy(this);
87 next.setTargetInstruction(targets[i]);
88 _cases.add(next);
89 }
90 invalidateByteIndexes();
91 return this;
92 }
93
94 public int[] getOffsets() {
95 int bi = getByteIndex();
96 int[] offsets = new int[_cases.size()];
97 for (int i = 0; i < offsets.length; i++)
98 offsets[i] = ((InstructionPtrStrategy) _cases.get(i)).getByteIndex()
99 - bi;
100 return offsets;
101 }
102
103 /***
104 * Return the values of the case statements for this switch.
105 */
106 public int[] getMatches() {
107 int[] matches = new int[_matches.size()];
108 Iterator itr = _matches.iterator();
109 for (int i = 0; i < matches.length; i++)
110 matches[i] = ((Integer) itr.next()).intValue();
111 return matches;
112 }
113
114 /***
115 * Return the targets of the case statements for this switch.
116 */
117 public Instruction[] getTargets() {
118 Instruction[] result = new Instruction[_cases.size()];
119 for (int i = 0; i < result.length; i++)
120 result[i] = ((InstructionPtrStrategy) _cases.get(i)).
121 getTargetInstruction();
122 return result;
123 }
124
125 /***
126 * Add a case to this switch.
127 *
128 * @return this instruction, for method chaining
129 */
130 public LookupSwitchInstruction addCase(int match, Instruction target) {
131 _matches.add(Numbers.valueOf(match));
132 _cases.add(new InstructionPtrStrategy(this, target));
133 invalidateByteIndexes();
134 return this;
135 }
136
137 private Instruction findJumpPoint(int jumpByteIndex, List inss) {
138 Instruction ins;
139 for (Iterator itr = inss.iterator(); itr.hasNext();) {
140 ins = (Instruction) itr.next();
141 if (ins.getByteIndex() == jumpByteIndex)
142 return ins;
143 }
144 return null;
145 }
146
147 public void updateTargets() {
148 super.updateTargets();
149 for (Iterator itr = _cases.iterator(); itr.hasNext();)
150 ((InstructionPtrStrategy) itr.next()).updateTargets();
151 }
152
153 public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
154 super.replaceTarget(oldTarget, newTarget);
155 for (Iterator itr = _cases.iterator(); itr.hasNext();)
156 ((InstructionPtrStrategy) itr.next()).replaceTarget(oldTarget,
157 newTarget);
158 }
159
160 public void acceptVisit(BCVisitor visit) {
161 visit.enterLookupSwitchInstruction(this);
162 visit.exitLookupSwitchInstruction(this);
163 }
164
165 void read(Instruction orig) {
166 super.read(orig);
167
168 LookupSwitchInstruction ins = (LookupSwitchInstruction) orig;
169 _matches = new LinkedList(ins._matches);
170 _cases.clear();
171 for (Iterator itr = ins._cases.iterator(); itr.hasNext();) {
172 InstructionPtrStrategy origPtr = (InstructionPtrStrategy)itr.next();
173 InstructionPtrStrategy newPtr = new InstructionPtrStrategy(this);
174 newPtr.setByteIndex(origPtr.getByteIndex());
175 _cases.add(newPtr);
176 }
177 invalidateByteIndexes();
178 }
179
180 void read(DataInput in) throws IOException {
181
182 int bi = getByteIndex();
183 for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++)
184 in.readByte();
185
186 setOffset(in.readInt());
187 _matches.clear();
188 _cases.clear();
189 for (int i = 0, pairCount = in.readInt(); i < pairCount; i++) {
190 _matches.add(Numbers.valueOf(in.readInt()));
191 InstructionPtrStrategy next = new InstructionPtrStrategy(this);
192 next.setByteIndex(bi + in.readInt());
193 _cases.add(next);
194 }
195 }
196
197 void write(DataOutput out) throws IOException {
198
199 int bi = getByteIndex();
200 for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++)
201 out.writeByte(0);
202
203 out.writeInt(getOffset());
204 out.writeInt(_matches.size());
205 for (int i = 0; i < _matches.size(); i++) {
206 out.writeInt(((Integer) _matches.get(i)).intValue());
207 out.writeInt(((InstructionPtrStrategy) _cases.get(i)).getByteIndex()
208 - bi);
209 }
210 }
211 }