1 package serp.bytecode;
2
3 import java.io.*;
4
5 import serp.bytecode.visitor.*;
6
7 /***
8 * The <code>wide</code> instruction, which is used to allow other
9 * instructions to index values beyond what they can normally index baed
10 * on the length of their arguments.
11 *
12 * @author Abe White
13 */
14 public class WideInstruction extends LocalVariableInstruction {
15 private static final Class[][] _mappings = new Class[][] {
16 { byte.class, int.class },
17 { boolean.class, int.class },
18 { char.class, int.class },
19 { short.class, int.class },
20 { void.class, int.class },
21 };
22 private int _ins = Constants.NOP;
23 private int _inc = -1;
24
25 WideInstruction(Code owner) {
26 super(owner, Constants.WIDE);
27 }
28
29 int getLength() {
30
31 int length = super.getLength() + 1 + 2;
32
33
34 if (_ins == Constants.IINC)
35 length += 2;
36 return length;
37 }
38
39 public int getStackChange() {
40 switch (_ins) {
41 case Constants.ILOAD:
42 case Constants.FLOAD:
43 case Constants.ALOAD:
44 return 1;
45 case Constants.LLOAD:
46 case Constants.DLOAD:
47 return 2;
48 case Constants.ISTORE:
49 case Constants.FSTORE:
50 case Constants.ASTORE:
51 return -1;
52 case Constants.LSTORE:
53 case Constants.DSTORE:
54 return -2;
55 default:
56 return 0;
57 }
58 }
59
60 public int getLogicalStackChange() {
61 switch (_ins) {
62 case Constants.ILOAD:
63 case Constants.FLOAD:
64 case Constants.ALOAD:
65 case Constants.LLOAD:
66 case Constants.DLOAD:
67 return 1;
68 case Constants.ISTORE:
69 case Constants.FSTORE:
70 case Constants.ASTORE:
71 case Constants.LSTORE:
72 case Constants.DSTORE:
73 return -1;
74 default:
75 return 0;
76 }
77 }
78
79 public String getTypeName() {
80 switch (_ins) {
81 case Constants.ILOAD:
82 case Constants.ISTORE:
83 return int.class.getName();
84 case Constants.LLOAD:
85 case Constants.LSTORE:
86 return long.class.getName();
87 case Constants.FLOAD:
88 case Constants.FSTORE:
89 return float.class.getName();
90 case Constants.DLOAD:
91 case Constants.DSTORE:
92 return double.class.getName();
93 case Constants.ALOAD:
94 case Constants.ASTORE:
95 return Object.class.getName();
96 default:
97 return null;
98 }
99 }
100
101 public TypedInstruction setType(String type) {
102 type = mapType(type, _mappings, true);
103 switch (_ins) {
104 case Constants.ILOAD:
105 case Constants.LLOAD:
106 case Constants.FLOAD:
107 case Constants.DLOAD:
108 case Constants.ALOAD:
109 if (type == null)
110 throw new IllegalStateException();
111 switch (type.charAt(0)) {
112 case 'i':
113 return (TypedInstruction) setInstruction(Constants.ILOAD);
114 case 'l':
115 return (TypedInstruction) setInstruction(Constants.LLOAD);
116 case 'f':
117 return (TypedInstruction) setInstruction(Constants.FLOAD);
118 case 'd':
119 return (TypedInstruction) setInstruction(Constants.DLOAD);
120 default:
121 return (TypedInstruction) setInstruction(Constants.ALOAD);
122 }
123 case Constants.ISTORE:
124 case Constants.LSTORE:
125 case Constants.FSTORE:
126 case Constants.DSTORE:
127 case Constants.ASTORE:
128 if (type == null)
129 throw new IllegalStateException();
130 switch (type.charAt(0)) {
131 case 'i':
132 return (TypedInstruction) setInstruction(Constants.ISTORE);
133 case 'l':
134 return (TypedInstruction) setInstruction(Constants.LSTORE);
135 case 'f':
136 return (TypedInstruction) setInstruction(Constants.FSTORE);
137 case 'd':
138 return (TypedInstruction) setInstruction(Constants.DSTORE);
139 default:
140 return (TypedInstruction) setInstruction(Constants.ASTORE);
141 }
142 default:
143 if (type != null)
144 throw new IllegalStateException("Augmented instruction not "
145 + "typed");
146 return this;
147 }
148 }
149
150 /***
151 * Return the opcode of the instruction to modify; this will return one
152 * of the constants defined in {@link Constants}.
153 */
154 public int getInstruction() {
155 return _ins;
156 }
157
158 /***
159 * Set the type of instruction this wide instruction modifies.
160 */
161 public WideInstruction setInstruction(Instruction ins) {
162 if (ins == null)
163 return setInstruction(Constants.NOP);
164 setInstruction(ins.getOpcode());
165 if (_ins == Constants.IINC)
166 _inc = ((IIncInstruction) ins).getIncrement();
167 return this;
168 }
169
170 /***
171 * Set the type of instruction this wide instruction modifies.
172 */
173 public WideInstruction setInstruction(int opcode) {
174 int len = getLength();
175 _ins = opcode;
176 if (len != getLength())
177 invalidateByteIndexes();
178 return this;
179 }
180
181 /***
182 * Set the type of instruction this wide instruction modifies.
183 *
184 * @return this instruction, for method chaining
185 */
186 public WideInstruction iinc() {
187 return setInstruction(Constants.IINC);
188 }
189
190 /***
191 * Set the type of instruction this wide instruction modifies.
192 *
193 * @return this instruction, for method chaining
194 */
195 public WideInstruction ret() {
196 return setInstruction(Constants.RET);
197 }
198
199 /***
200 * Set the type of instruction this wide instruction modifies.
201 *
202 * @return this instruction, for method chaining
203 */
204 public WideInstruction iload() {
205 return setInstruction(Constants.ILOAD);
206 }
207
208 /***
209 * Set the type of instruction this wide instruction modifies.
210 *
211 * @return this instruction, for method chaining
212 */
213 public WideInstruction fload() {
214 return setInstruction(Constants.FLOAD);
215 }
216
217 /***
218 * Set the type of instruction this wide instruction modifies.
219 *
220 * @return this instruction, for method chaining
221 */
222 public WideInstruction aload() {
223 return setInstruction(Constants.ALOAD);
224 }
225
226 /***
227 * Set the type of instruction this wide instruction modifies.
228 *
229 * @return this instruction, for method chaining
230 */
231 public WideInstruction lload() {
232 return setInstruction(Constants.LLOAD);
233 }
234
235 /***
236 * Set the type of instruction this wide instruction modifies.
237 *
238 * @return this instruction, for method chaining
239 */
240 public WideInstruction dload() {
241 return setInstruction(Constants.DLOAD);
242 }
243
244 /***
245 * Set the type of instruction this wide instruction modifies.
246 *
247 * @return this instruction, for method chaining
248 */
249 public WideInstruction istore() {
250 return setInstruction(Constants.ISTORE);
251 }
252
253 /***
254 * Set the type of instruction this wide instruction modifies.
255 *
256 * @return this instruction, for method chaining
257 */
258 public WideInstruction fstore() {
259 return setInstruction(Constants.FSTORE);
260 }
261
262 /***
263 * Set the type of instruction this wide instruction modifies.
264 *
265 * @return this instruction, for method chaining
266 */
267 public WideInstruction astore() {
268 return setInstruction(Constants.ASTORE);
269 }
270
271 /***
272 * Set the type of instruction this wide instruction modifies.
273 *
274 * @return this instruction, for method chaining
275 */
276 public WideInstruction lstore() {
277 return setInstruction(Constants.LSTORE);
278 }
279
280 /***
281 * Set the type of instruction this wide instruction modifies.
282 *
283 * @return this instruction, for method chaining
284 */
285 public WideInstruction dstore() {
286 return setInstruction(Constants.DSTORE);
287 }
288
289 /***
290 * Return the increment for this instruction if it augments IINC, or -1
291 * if unset.
292 */
293 public int getIncrement() {
294 return _inc;
295 }
296
297 /***
298 * Set the increment on this instruction if it augments IINC.
299 *
300 * @return this Instruction, for method chaining
301 */
302 public WideInstruction setIncrement(int val) {
303 _inc = val;
304 return this;
305 }
306
307 /***
308 * WideInstructions are equal if the instruction they augment is the same
309 * or unset.
310 */
311 public boolean equalsInstruction(Instruction other) {
312 if (other == this)
313 return true;
314 if (!super.equalsInstruction(other))
315 return false;
316 if (!(other instanceof WideInstruction))
317 return false;
318
319 WideInstruction ins = (WideInstruction) other;
320 int code = getInstruction();
321 int otherCode = ins.getInstruction();
322 if (code != otherCode)
323 return false;
324 if (code == Constants.IINC) {
325 int inc = getIncrement();
326 int otherInc = ins.getIncrement();
327 return (inc == -1) || (otherInc == -1) || (inc == otherInc);
328 }
329 return true;
330 }
331
332 public void acceptVisit(BCVisitor visit) {
333 visit.enterWideInstruction(this);
334 visit.exitWideInstruction(this);
335 }
336
337 void read(Instruction orig) {
338 super.read(orig);
339 setInstruction(((WideInstruction) orig).getInstruction());
340 }
341
342 void read(DataInput in) throws IOException {
343 super.read(in);
344 _ins = in.readUnsignedByte();
345 setLocal(in.readUnsignedShort());
346 if (_ins == Constants.IINC)
347 _inc = in.readUnsignedShort();
348 }
349
350 void write(DataOutput out) throws IOException {
351 super.write(out);
352 out.writeByte(_ins);
353 out.writeShort(getLocal());
354 if (_ins == Constants.IINC)
355 out.writeShort(_inc);
356 }
357 }