View Javadoc

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          // opcode, ins, index
31          int length = super.getLength() + 1 + 2;
32  
33          // increment
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 }