001 package serp.bytecode;
002
003 import java.io.*;
004
005 import serp.bytecode.visitor.*;
006
007 /**
008 * The <code>wide</code> instruction, which is used to allow other
009 * instructions to index values beyond what they can normally index baed
010 * on the length of their arguments.
011 *
012 * @author Abe White
013 */
014 public class WideInstruction extends LocalVariableInstruction {
015 private static final Class[][] _mappings = new Class[][] {
016 { byte.class, int.class },
017 { boolean.class, int.class },
018 { char.class, int.class },
019 { short.class, int.class },
020 { void.class, int.class },
021 };
022 private int _ins = Constants.NOP;
023 private int _inc = -1;
024
025 WideInstruction(Code owner) {
026 super(owner, Constants.WIDE);
027 }
028
029 int getLength() {
030 // opcode, ins, index
031 int length = super.getLength() + 1 + 2;
032
033 // increment
034 if (_ins == Constants.IINC)
035 length += 2;
036 return length;
037 }
038
039 public int getStackChange() {
040 switch (_ins) {
041 case Constants.ILOAD:
042 case Constants.FLOAD:
043 case Constants.ALOAD:
044 return 1;
045 case Constants.LLOAD:
046 case Constants.DLOAD:
047 return 2;
048 case Constants.ISTORE:
049 case Constants.FSTORE:
050 case Constants.ASTORE:
051 return -1;
052 case Constants.LSTORE:
053 case Constants.DSTORE:
054 return -2;
055 default:
056 return 0;
057 }
058 }
059
060 public int getLogicalStackChange() {
061 switch (_ins) {
062 case Constants.ILOAD:
063 case Constants.FLOAD:
064 case Constants.ALOAD:
065 case Constants.LLOAD:
066 case Constants.DLOAD:
067 return 1;
068 case Constants.ISTORE:
069 case Constants.FSTORE:
070 case Constants.ASTORE:
071 case Constants.LSTORE:
072 case Constants.DSTORE:
073 return -1;
074 default:
075 return 0;
076 }
077 }
078
079 public String getTypeName() {
080 switch (_ins) {
081 case Constants.ILOAD:
082 case Constants.ISTORE:
083 return int.class.getName();
084 case Constants.LLOAD:
085 case Constants.LSTORE:
086 return long.class.getName();
087 case Constants.FLOAD:
088 case Constants.FSTORE:
089 return float.class.getName();
090 case Constants.DLOAD:
091 case Constants.DSTORE:
092 return double.class.getName();
093 case Constants.ALOAD:
094 case Constants.ASTORE:
095 return Object.class.getName();
096 default:
097 return null;
098 }
099 }
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 }