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
115 if (type == null || local < 0) {
116 _type = type;
117 setOpcode(Constants.NOP);
118 } else {
119
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
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 }