001 package serp.bytecode;
002
003 import java.io.*;
004
005 import serp.bytecode.visitor.*;
006
007 /**
008 * An instruction to store a value from a local variable onto the stack.
009 *
010 * @author Abe White
011 */
012 public class StoreInstruction extends LocalVariableInstruction {
013 private static final Class[][] _mappings = new Class[][] {
014 { byte.class, int.class },
015 { boolean.class, int.class },
016 { char.class, int.class },
017 { short.class, int.class },
018 { void.class, int.class },
019 };
020 String _type = null;
021
022 StoreInstruction(Code owner) {
023 super(owner);
024 }
025
026 StoreInstruction(Code owner, int opcode) {
027 super(owner, opcode);
028 }
029
030 int getLength() {
031 switch (getOpcode()) {
032 case Constants.ISTORE:
033 case Constants.LSTORE:
034 case Constants.FSTORE:
035 case Constants.DSTORE:
036 case Constants.ASTORE:
037 return super.getLength() + 1;
038 default:
039 return super.getLength();
040 }
041 }
042
043 public int getLogicalStackChange() {
044 switch (getOpcode()) {
045 case Constants.NOP:
046 return 0;
047 default:
048 return -1;
049 }
050 }
051
052 public int getStackChange() {
053 switch (getOpcode()) {
054 case Constants.LSTORE:
055 case Constants.LSTORE0:
056 case Constants.LSTORE1:
057 case Constants.LSTORE2:
058 case Constants.LSTORE3:
059 case Constants.DSTORE:
060 case Constants.DSTORE0:
061 case Constants.DSTORE1:
062 case Constants.DSTORE2:
063 case Constants.DSTORE3:
064 return -2;
065 case Constants.NOP:
066 return 0;
067 default:
068 return -1;
069 }
070 }
071
072 public String getTypeName() {
073 switch (getOpcode()) {
074 case Constants.ISTORE:
075 case Constants.ISTORE0:
076 case Constants.ISTORE1:
077 case Constants.ISTORE2:
078 case Constants.ISTORE3:
079 return int.class.getName();
080 case Constants.LSTORE:
081 case Constants.LSTORE0:
082 case Constants.LSTORE1:
083 case Constants.LSTORE2:
084 case Constants.LSTORE3:
085 return long.class.getName();
086 case Constants.FSTORE:
087 case Constants.FSTORE0:
088 case Constants.FSTORE1:
089 case Constants.FSTORE2:
090 case Constants.FSTORE3:
091 return float.class.getName();
092 case Constants.DSTORE:
093 case Constants.DSTORE0:
094 case Constants.DSTORE1:
095 case Constants.DSTORE2:
096 case Constants.DSTORE3:
097 return double.class.getName();
098 case Constants.ASTORE:
099 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 }