View Javadoc

1   package serp.bytecode;
2   
3   import java.io.*;
4   
5   import serp.bytecode.visitor.*;
6   
7   /***
8    * Loads a value from the locals table to the stack.
9    *
10   * @author Abe White
11   */
12  public class LoadInstruction extends LocalVariableInstruction {
13      private static final Class[][] _mappings = new Class[][] {
14          { byte.class, int.class },
15          { boolean.class, int.class },
16          { char.class, int.class },
17          { short.class, int.class },
18          { void.class, int.class },
19      };
20      String _type = null;
21  
22      LoadInstruction(Code owner) {
23          super(owner);
24      }
25  
26      LoadInstruction(Code owner, int opcode) {
27          super(owner, opcode);
28      }
29  
30      int getLength() {
31          switch (getOpcode()) {
32          case Constants.ILOAD:
33          case Constants.LLOAD:
34          case Constants.FLOAD:
35          case Constants.DLOAD:
36          case Constants.ALOAD:
37              return super.getLength() + 1;
38          default:
39              return super.getLength();
40          }
41      }
42  
43      public int getStackChange() {
44          switch (getOpcode()) {
45          case Constants.LLOAD:
46          case Constants.LLOAD0:
47          case Constants.LLOAD1:
48          case Constants.LLOAD2:
49          case Constants.LLOAD3:
50          case Constants.DLOAD:
51          case Constants.DLOAD0:
52          case Constants.DLOAD1:
53          case Constants.DLOAD2:
54          case Constants.DLOAD3:
55              return 2;
56          case Constants.NOP:
57              return 0;
58          default:
59              return 1;
60          }
61      }
62  
63      public int getLogicalStackChange() {
64          switch (getOpcode()) {
65          case Constants.NOP:
66              return 0;
67          default:
68              return 1;
69          }
70      }
71  
72      public String getTypeName() {
73          switch (getOpcode()) {
74          case Constants.ILOAD:
75          case Constants.ILOAD0:
76          case Constants.ILOAD1:
77          case Constants.ILOAD2:
78          case Constants.ILOAD3:
79              return int.class.getName();
80          case Constants.LLOAD:
81          case Constants.LLOAD0:
82          case Constants.LLOAD1:
83          case Constants.LLOAD2:
84          case Constants.LLOAD3:
85              return long.class.getName();
86          case Constants.FLOAD:
87          case Constants.FLOAD0:
88          case Constants.FLOAD1:
89          case Constants.FLOAD2:
90          case Constants.FLOAD3:
91              return float.class.getName();
92          case Constants.DLOAD:
93          case Constants.DLOAD0:
94          case Constants.DLOAD1:
95          case Constants.DLOAD2:
96          case Constants.DLOAD3:
97              return double.class.getName();
98          case Constants.ALOAD:
99          case Constants.ALOAD0:
100         case Constants.ALOAD1:
101         case Constants.ALOAD2:
102         case Constants.ALOAD3:
103             return Object.class.getName();
104         default:
105             return _type;
106         }
107     }
108 
109     public TypedInstruction setType(String type) {
110         type = mapType(type, _mappings, true);
111         int local = getLocal();
112         int len = getLength();
113 
114         // if an invalid type or local, revert to nop
115         if (type == null || local < 0) {
116             _type = type;
117             setOpcode(Constants.NOP);
118         } else {
119             // valid opcode, unset saved type
120             _type = null;
121             switch (type.charAt(0)) {
122             case 'i':
123                 setOpcode((local > 3) ? Constants.ILOAD
124                     : (Constants.ILOAD0 + local));
125                 break;
126             case 'l':
127                 setOpcode((local > 3) ? Constants.LLOAD
128                     : (Constants.LLOAD0 + local));
129                 break;
130             case 'f':
131                 setOpcode((local > 3) ? Constants.FLOAD
132                     : (Constants.FLOAD0 + local));
133                 break;
134             case 'd':
135                 setOpcode((local > 3) ? Constants.DLOAD
136                     : (Constants.DLOAD0 + local));
137                 break;
138             default:
139                 setOpcode((local > 3) ? Constants.ALOAD
140                     : (Constants.ALOAD0 + local));
141             }
142         }
143         if (len != getLength())
144             invalidateByteIndexes();
145         return this;
146     }
147 
148     /***
149      * Equivalent to <code>setLocal (0).setType (Object.class)</code>; the
150      * <code>this</code> ptr is always passed in local variable 0.
151      *
152      * @return this instruction, for method chaining
153      */
154     public LoadInstruction setThis() {
155         return (LoadInstruction) setLocal(0).setType(Object.class);
156     }
157 
158     /***
159      * Equivalent to <code>getLocal () == 0 && getType () ==
160      * Object.class</code>; the <code>this</code> ptr
161      * is always passed in local variable 0.
162      */
163     public boolean isThis() {
164         return getLocal() == 0 && getType() == Object.class;
165     }
166 
167     /***
168      * LoadInstructions are equal if the type they reference the same
169      * type and locals index or if either is unset.
170      */
171     public boolean equalsInstruction(Instruction other) {
172         if (other == this)
173             return true;
174         if (!super.equalsInstruction(other))
175             return false;
176 
177         String type = getTypeName();
178         String otherType = ((LoadInstruction) other).getTypeName();
179         return type == null || otherType == null || type.equals(otherType);
180     }
181 
182     public void acceptVisit(BCVisitor visit) {
183         visit.enterLoadInstruction(this);
184         visit.exitLoadInstruction(this);
185     }
186 
187     void read(Instruction orig) {
188         super.read(orig);
189         LoadInstruction ins = (LoadInstruction) orig;
190         _type = ins._type;
191     }
192 
193     void read(DataInput in) throws IOException {
194         super.read(in);
195         switch (getOpcode()) {
196         case Constants.ILOAD:
197         case Constants.LLOAD:
198         case Constants.FLOAD:
199         case Constants.DLOAD:
200         case Constants.ALOAD:
201             setLocal(in.readUnsignedByte());
202             break;
203         }
204     }
205 
206     void write(DataOutput out) throws IOException {
207         super.write(out);
208         switch (getOpcode()) {
209         case Constants.ILOAD:
210         case Constants.LLOAD:
211         case Constants.FLOAD:
212         case Constants.DLOAD:
213         case Constants.ALOAD:
214             out.writeByte(getLocal());
215         }
216     }
217 
218     void calculateOpcode() {
219         // taken care of when setting type
220         setType(getTypeName());
221     }
222 
223     void calculateLocal() {
224         switch (getOpcode()) {
225         case Constants.ILOAD0:
226         case Constants.LLOAD0:
227         case Constants.FLOAD0:
228         case Constants.DLOAD0:
229         case Constants.ALOAD0:
230             setLocal(0);
231             break;
232         case Constants.ILOAD1:
233         case Constants.LLOAD1:
234         case Constants.FLOAD1:
235         case Constants.DLOAD1:
236         case Constants.ALOAD1:
237             setLocal(1);
238             break;
239         case Constants.ILOAD2:
240         case Constants.LLOAD2:
241         case Constants.FLOAD2:
242         case Constants.DLOAD2:
243         case Constants.ALOAD2:
244             setLocal(2);
245             break;
246         case Constants.ILOAD3:
247         case Constants.LLOAD3:
248         case Constants.FLOAD3:
249         case Constants.DLOAD3:
250         case Constants.ALOAD3:
251             setLocal(3);
252             break;
253         }
254     }
255 }