View Javadoc

1   package serp.bytecode;
2   
3   import java.io.*;
4   
5   import serp.bytecode.visitor.*;
6   
7   /***
8    * An instruction to store a value from a local variable onto the stack.
9    *
10   * @author Abe White
11   */
12  public class StoreInstruction 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      StoreInstruction(Code owner) {
23          super(owner);
24      }
25  
26      StoreInstruction(Code owner, int opcode) {
27          super(owner, opcode);
28      }
29  
30      int getLength() {
31          switch (getOpcode()) {
32          case Constants.ISTORE:
33          case Constants.LSTORE:
34          case Constants.FSTORE:
35          case Constants.DSTORE:
36          case Constants.ASTORE:
37              return super.getLength() + 1;
38          default:
39              return super.getLength();
40          }
41      }
42  
43      public int getLogicalStackChange() {
44          switch (getOpcode()) {
45          case Constants.NOP:
46              return 0;
47          default:
48              return -1;
49          }
50      }
51  
52      public int getStackChange() {
53          switch (getOpcode()) {
54          case Constants.LSTORE:
55          case Constants.LSTORE0:
56          case Constants.LSTORE1:
57          case Constants.LSTORE2:
58          case Constants.LSTORE3:
59          case Constants.DSTORE:
60          case Constants.DSTORE0:
61          case Constants.DSTORE1:
62          case Constants.DSTORE2:
63          case Constants.DSTORE3:
64              return -2;
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.ISTORE:
75          case Constants.ISTORE0:
76          case Constants.ISTORE1:
77          case Constants.ISTORE2:
78          case Constants.ISTORE3:
79              return int.class.getName();
80          case Constants.LSTORE:
81          case Constants.LSTORE0:
82          case Constants.LSTORE1:
83          case Constants.LSTORE2:
84          case Constants.LSTORE3:
85              return long.class.getName();
86          case Constants.FSTORE:
87          case Constants.FSTORE0:
88          case Constants.FSTORE1:
89          case Constants.FSTORE2:
90          case Constants.FSTORE3:
91              return float.class.getName();
92          case Constants.DSTORE:
93          case Constants.DSTORE0:
94          case Constants.DSTORE1:
95          case Constants.DSTORE2:
96          case Constants.DSTORE3:
97              return double.class.getName();
98          case Constants.ASTORE:
99          case Constants.ASTORE0:
100         case Constants.ASTORE1:
101         case Constants.ASTORE2:
102         case Constants.ASTORE3:
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.ISTORE
124                     : (Constants.ISTORE0 + local));
125                 break;
126             case 'l':
127                 setOpcode((local > 3) ? Constants.LSTORE
128                     : (Constants.LSTORE0 + local));
129                 break;
130             case 'f':
131                 setOpcode((local > 3) ? Constants.FSTORE
132                     : (Constants.FSTORE0 + local));
133                 break;
134             case 'd':
135                 setOpcode((local > 3) ? Constants.DSTORE
136                     : (Constants.DSTORE0 + local));
137                 break;
138             default:
139                 setOpcode((local > 3) ? Constants.ASTORE
140                     : (Constants.ASTORE0 + local));
141                 break;
142             }
143         }
144         if (len != getLength())
145             invalidateByteIndexes();
146         return this;
147     }
148 
149     /***
150      * StoreInstructions are equal if the type they reference the same
151      * type and locals index or if either is unset.
152      */
153     public boolean equalsInstruction(Instruction other) {
154         if (other == this)
155             return true;
156         if (!super.equalsInstruction(other))
157             return false;
158 
159         String type = getTypeName();
160         String otherType = ((StoreInstruction) other).getTypeName();
161         return type == null || otherType == null || type.equals(otherType);
162     }
163 
164     public void acceptVisit(BCVisitor visit) {
165         visit.enterStoreInstruction(this);
166         visit.exitStoreInstruction(this);
167     }
168 
169     void read(Instruction orig) {
170         super.read(orig);
171         StoreInstruction ins = (StoreInstruction) orig;
172         _type = ins._type;
173     }
174 
175     void read(DataInput in) throws IOException {
176         super.read(in);
177         switch (getOpcode()) {
178         case Constants.ISTORE:
179         case Constants.LSTORE:
180         case Constants.FSTORE:
181         case Constants.DSTORE:
182         case Constants.ASTORE:
183             setLocal(in.readUnsignedByte());
184             break;
185         }
186     }
187 
188     void write(DataOutput out) throws IOException {
189         super.write(out);
190         switch (getOpcode()) {
191         case Constants.ISTORE:
192         case Constants.LSTORE:
193         case Constants.FSTORE:
194         case Constants.DSTORE:
195         case Constants.ASTORE:
196             out.writeByte(getLocal());
197         }
198     }
199 
200     void calculateOpcode() {
201         // taken care of when setting type
202         setType(getTypeName());
203     }
204 
205     void calculateLocal() {
206         switch (getOpcode()) {
207         case Constants.ISTORE0:
208         case Constants.LSTORE0:
209         case Constants.FSTORE0:
210         case Constants.DSTORE0:
211         case Constants.ASTORE0:
212             setLocal(0);
213             break;
214         case Constants.ISTORE1:
215         case Constants.LSTORE1:
216         case Constants.FSTORE1:
217         case Constants.DSTORE1:
218         case Constants.ASTORE1:
219             setLocal(1);
220             break;
221         case Constants.ISTORE2:
222         case Constants.LSTORE2:
223         case Constants.FSTORE2:
224         case Constants.DSTORE2:
225         case Constants.ASTORE2:
226             setLocal(2);
227             break;
228         case Constants.ISTORE3:
229         case Constants.LSTORE3:
230         case Constants.FSTORE3:
231         case Constants.DSTORE3:
232         case Constants.ASTORE3:
233             setLocal(3);
234             break;
235         }
236     }
237 }