1 package serp.bytecode;
2
3 import java.io.*;
4 import java.lang.reflect.*;
5
6 import serp.bytecode.lowlevel.*;
7 import serp.bytecode.visitor.*;
8 import serp.util.*;
9
10 /***
11 * Instruction that takes as an argument a field to operate
12 * on. Examples include <code>getfield, getstatic, setfield, setstatic</code>.
13 *
14 * @author Abe White
15 */
16 public abstract class FieldInstruction extends Instruction {
17 private int _index = 0;
18
19 FieldInstruction(Code owner, int opcode) {
20 super(owner, opcode);
21 }
22
23 int getLength() {
24 return super.getLength() + 2;
25 }
26
27
28
29
30
31 /***
32 * Return the index in the class {@link ConstantPool} of the
33 * {@link ComplexEntry} describing the field to operate on.
34 */
35 public int getFieldIndex() {
36 return _index;
37 }
38
39 /***
40 * Set the index in the class {@link ConstantPool} of the
41 * {@link ComplexEntry} describing the field to operate on.
42 *
43 * @return this instruction, for method chaining
44 */
45 public FieldInstruction setFieldIndex(int index) {
46 _index = index;
47 return this;
48 }
49
50 /***
51 * Return the field this instruction operates on, or null if not set.
52 */
53 public BCField getField() {
54 String dec = getFieldDeclarerName();
55 if (dec == null)
56 return null;
57
58 BCClass bc = getProject().loadClass(dec, getClassLoader());
59 BCField[] fields = bc.getFields(getFieldName());
60 if (fields.length == 0)
61 return null;
62 return fields[0];
63 }
64
65 /***
66 * Set the field this instruction operates on.
67 *
68 * @return this instruction, for method chaining
69 */
70 public FieldInstruction setField(BCField field) {
71 if (field == null)
72 return setFieldIndex(0);
73 return setField(field.getDeclarer().getName(), field.getName(),
74 field.getTypeName());
75 }
76
77 /***
78 * Set the field this instruction operates on.
79 *
80 * @return this instruction, for method chaining
81 */
82 public FieldInstruction setField(Field field) {
83 if (field == null)
84 return setFieldIndex(0);
85 return setField(field.getDeclaringClass(), field.getName(),
86 field.getType());
87 }
88
89 /***
90 * Set the field this instruction operates on.
91 *
92 * @param dec the full class name of the field's declaring class
93 * @param name the field name
94 * @param type the full class name of the field type
95 * @return this instruction, for method chaining
96 */
97 public FieldInstruction setField(String dec, String name, String type) {
98 if (dec == null && name == null && type == null)
99 return setFieldIndex(0);
100 if (dec == null)
101 dec = "";
102 if (name == null)
103 name = "";
104 if (type == null)
105 type = "";
106
107 dec = getProject().getNameCache().getInternalForm(dec, false);
108 type = getProject().getNameCache().getInternalForm(type, true);
109 return setFieldIndex(getPool().findFieldEntry(dec, name, type, true));
110 }
111
112 /***
113 * Set the field this instruction operates on, for fields that are
114 * declared by the current class.
115 *
116 * @param name the field name
117 * @param type the full class name of the field type
118 * @return this instruction, for method chaining
119 */
120 public FieldInstruction setField(String name, String type) {
121 BCClass owner = getCode().getMethod().getDeclarer();
122 return setField(owner.getName(), name, type);
123 }
124
125 /***
126 * Set the field this instruction operates on.
127 *
128 * @param dec the field's declaring class
129 * @param name the field name
130 * @param type the class of the field type
131 * @return this instruction, for method chaining
132 */
133 public FieldInstruction setField(Class dec, String name, Class type) {
134 String decName = (dec == null) ? null : dec.getName();
135 String typeName = (type == null) ? null : type.getName();
136 return setField(decName, name, typeName);
137 }
138
139 /***
140 * Set the field this instruction operates on, for fields that are
141 * declared by the current class.
142 *
143 * @param name the field name
144 * @param type the class of the field type
145 * @return this instruction, for method chaining
146 */
147 public FieldInstruction setField(String name, Class type) {
148 BCClass owner = getCode().getMethod().getDeclarer();
149 String typeName = (type == null) ? null : type.getName();
150 return setField(owner.getName(), name, typeName);
151 }
152
153 /***
154 * Set the field this instruction operates on.
155 *
156 * @param dec the field's declaring class
157 * @param name the field name
158 * @param type the class of the field type
159 * @return this instruction, for method chaining
160 */
161 public FieldInstruction setField(BCClass dec, String name, BCClass type) {
162 String decName = (dec == null) ? null : dec.getName();
163 String typeName = (type == null) ? null : type.getName();
164 return setField(decName, name, typeName);
165 }
166
167 /***
168 * Set the field this instruction operates on, for fields that are
169 * declared by the current class.
170 *
171 * @param name the field name
172 * @param type the class of the field type
173 * @return this instruction, for method chaining
174 */
175 public FieldInstruction setField(String name, BCClass type) {
176 BCClass owner = getCode().getMethod().getDeclarer();
177 String typeName = (type == null) ? null : type.getName();
178 return setField(owner.getName(), name, typeName);
179 }
180
181
182
183
184
185 /***
186 * Return the name of the field this instruction operates on, or null
187 * if not set.
188 */
189 public String getFieldName() {
190 int index = getFieldIndex();
191 if (index == 0)
192 return null;
193
194 ComplexEntry entry = (ComplexEntry) getPool().getEntry(index);
195 String name = entry.getNameAndTypeEntry().getNameEntry().getValue();
196 if (name.length() == 0)
197 return null;
198 return name;
199 }
200
201 /***
202 * Set the name of the field this instruction operates on.
203 *
204 * @return this instruction, for method chaining
205 */
206 public FieldInstruction setFieldName(String name) {
207 return setField(getFieldDeclarerName(), name, getFieldTypeName());
208 }
209
210 /***
211 * Return the type of the field this instruction operates on, or null
212 * if not set.
213 */
214 public String getFieldTypeName() {
215 int index = getFieldIndex();
216 if (index == 0)
217 return null;
218
219 ComplexEntry entry = (ComplexEntry) getPool().getEntry(index);
220 String name = getProject().getNameCache().getExternalForm(entry.
221 getNameAndTypeEntry().getDescriptorEntry().getValue(), false);
222 if (name.length() == 0)
223 return null;
224 return name;
225 }
226
227 /***
228 * Return the type of the field this instruction operates on, or null
229 * if not set.
230 */
231 public Class getFieldType() {
232 String type = getFieldTypeName();
233 if (type == null)
234 return null;
235 return Strings.toClass(type, getClassLoader());
236 }
237
238 /***
239 * Return the type of the field this instruction operates on, or null
240 * if not set.
241 */
242 public BCClass getFieldTypeBC() {
243 String type = getFieldTypeName();
244 if (type == null)
245 return null;
246 return getProject().loadClass(type, getClassLoader());
247 }
248
249 /***
250 * Set the type of the field this instruction operates on.
251 *
252 * @return this instruction, for method chaining
253 */
254 public FieldInstruction setFieldType(String type) {
255 return setField(getFieldDeclarerName(), getFieldName(), type);
256 }
257
258 /***
259 * Set the type of the field this instruction operates on.
260 *
261 * @return this instruction, for method chaining
262 */
263 public FieldInstruction setFieldType(Class type) {
264 String name = null;
265 if (type != null)
266 name = type.getName();
267 return setFieldType(name);
268 }
269
270 /***
271 * Set the type of the field this instruction operates on.
272 *
273 * @return this instruction, for method chaining
274 */
275 public FieldInstruction setFieldType(BCClass type) {
276 String name = null;
277 if (type != null)
278 name = type.getName();
279 return setFieldType(name);
280 }
281
282 /***
283 * Return the declaring class of the field this instruction operates on,
284 * or null if not set.
285 */
286 public String getFieldDeclarerName() {
287 int index = getFieldIndex();
288 if (index == 0)
289 return null;
290
291 ComplexEntry entry = (ComplexEntry) getPool().getEntry(index);
292 String name = getProject().getNameCache().getExternalForm(entry.
293 getClassEntry().getNameEntry().getValue(), false);
294 if (name.length() == 0)
295 return null;
296 return name;
297 }
298
299 /***
300 * Return the declaring class of the field this instruction operates on,
301 * or null if not set.
302 */
303 public Class getFieldDeclarerType() {
304 String type = getFieldDeclarerName();
305 if (type == null)
306 return null;
307 return Strings.toClass(type, getClassLoader());
308 }
309
310 /***
311 * Return the declaring class of the field this instruction operates on,
312 * or null if not set.
313 */
314 public BCClass getFieldDeclarerBC() {
315 String type = getFieldDeclarerName();
316 if (type == null)
317 return null;
318 return getProject().loadClass(type, getClassLoader());
319 }
320
321 /***
322 * Set the declaring class of the field this instruction operates on.
323 *
324 * @return this instruction, for method chaining
325 */
326 public FieldInstruction setFieldDeclarer(String type) {
327 return setField(type, getFieldName(), getFieldTypeName());
328 }
329
330 /***
331 * Set the declaring class of the field this instruction operates on.
332 *
333 * @return this instruction, for method chaining
334 */
335 public FieldInstruction setFieldDeclarer(Class type) {
336 String name = null;
337 if (type != null)
338 name = type.getName();
339 return setFieldDeclarer(name);
340 }
341
342 /***
343 * Set the declaring class of the field this instruction operates on.
344 *
345 * @return this instruction, for method chaining
346 */
347 public FieldInstruction setFieldDeclarer(BCClass type) {
348 String name = null;
349 if (type != null)
350 name = type.getName();
351 return setFieldDeclarer(name);
352 }
353
354 /***
355 * FieldInstructions are equal if the field they reference is the same,
356 * or if the field of either is unset.
357 */
358 public boolean equalsInstruction(Instruction other) {
359 if (other == this)
360 return true;
361 if (!(other instanceof FieldInstruction))
362 return false;
363 if (!super.equalsInstruction(other))
364 return false;
365
366 FieldInstruction ins = (FieldInstruction) other;
367 String s1 = getFieldName();
368 String s2 = ins.getFieldName();
369 if (!(s1 == null || s2 == null || s1.equals(s2)))
370 return false;
371
372 s1 = getFieldTypeName();
373 s2 = ins.getFieldTypeName();
374 if (!(s1 == null || s2 == null || s1.equals(s2)))
375 return false;
376
377 s1 = getFieldDeclarerName();
378 s2 = ins.getFieldDeclarerName();
379 if (!(s1 == null || s2 == null || s1.equals(s2)))
380 return false;
381 return true;
382 }
383
384 void read(Instruction orig) {
385 super.read(orig);
386 FieldInstruction ins = (FieldInstruction) orig;
387 setField(ins.getFieldDeclarerName(), ins.getFieldName(),
388 ins.getFieldTypeName());
389 }
390
391 void read(DataInput in) throws IOException {
392 super.read(in);
393 setFieldIndex(in.readUnsignedShort());
394 }
395
396 void write(DataOutput out) throws IOException {
397 super.write(out);
398 out.writeShort(getFieldIndex());
399 }
400 }