001 package serp.bytecode;
002
003 import java.io.*;
004
005 import serp.bytecode.visitor.*;
006
007 /**
008 * Loads a value from the locals table to the stack.
009 *
010 * @author Abe White
011 */
012 public class LoadInstruction 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 LoadInstruction(Code owner) {
023 super(owner);
024 }
025
026 LoadInstruction(Code owner, int opcode) {
027 super(owner, opcode);
028 }
029
030 int getLength() {
031 switch (getOpcode()) {
032 case Constants.ILOAD:
033 case Constants.LLOAD:
034 case Constants.FLOAD:
035 case Constants.DLOAD:
036 case Constants.ALOAD:
037 return super.getLength() + 1;
038 default:
039 return super.getLength();
040 }
041 }
042
043 public int getStackChange() {
044 switch (getOpcode()) {
045 case Constants.LLOAD:
046 case Constants.LLOAD0:
047 case Constants.LLOAD1:
048 case Constants.LLOAD2:
049 case Constants.LLOAD3:
050 case Constants.DLOAD:
051 case Constants.DLOAD0:
052 case Constants.DLOAD1:
053 case Constants.DLOAD2:
054 case Constants.DLOAD3:
055 return 2;
056 case Constants.NOP:
057 return 0;
058 default:
059 return 1;
060 }
061 }
062
063 public int getLogicalStackChange() {
064 switch (getOpcode()) {
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.ILOAD:
075 case Constants.ILOAD0:
076 case Constants.ILOAD1:
077 case Constants.ILOAD2:
078 case Constants.ILOAD3:
079 return int.class.getName();
080 case Constants.LLOAD:
081 case Constants.LLOAD0:
082 case Constants.LLOAD1:
083 case Constants.LLOAD2:
084 case Constants.LLOAD3:
085 return long.class.getName();
086 case Constants.FLOAD:
087 case Constants.FLOAD0:
088 case Constants.FLOAD1:
089 case Constants.FLOAD2:
090 case Constants.FLOAD3:
091 return float.class.getName();
092 case Constants.DLOAD:
093 case Constants.DLOAD0:
094 case Constants.DLOAD1:
095 case Constants.DLOAD2:
096 case Constants.DLOAD3:
097 return double.class.getName();
098 case Constants.ALOAD:
099 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 }