1 package serp.bytecode;
2
3 import java.io.*;
4
5 import serp.bytecode.lowlevel.*;
6 import serp.bytecode.visitor.*;
7 import serp.util.*;
8
9
10
11
12
13
14
15
16
17
18 public class ConstantInstruction extends TypedInstruction {
19 private int _arg = -1;
20
21 ConstantInstruction(Code owner) {
22 super(owner);
23 }
24
25 ConstantInstruction(Code owner, int opcode) {
26 super(owner, opcode);
27 }
28
29 int getLength() {
30 switch (getOpcode()) {
31 case Constants.BIPUSH:
32 case Constants.LDC:
33 return super.getLength() + 1;
34 case Constants.SIPUSH:
35 case Constants.LDCW:
36 case Constants.LDC2W:
37 return super.getLength() + 2;
38 default:
39 return super.getLength();
40 }
41 }
42
43 public int getStackChange() {
44 String type = getTypeName();
45 if (double.class.getName().equals(type)
46 || long.class.getName().equals(type))
47 return 2;
48 return 1;
49 }
50
51 public int getLogicalStackChange() {
52 return 1;
53 }
54
55 public String getTypeName() {
56 int opcode = getOpcode();
57 switch (opcode) {
58 case Constants.NOP:
59 return null;
60 case Constants.ACONSTNULL:
61 return Object.class.getName();
62 case Constants.ICONSTM1:
63 case Constants.ICONST0:
64 case Constants.ICONST1:
65 case Constants.ICONST2:
66 case Constants.ICONST3:
67 case Constants.ICONST4:
68 case Constants.ICONST5:
69 case Constants.BIPUSH:
70 case Constants.SIPUSH:
71 return int.class.getName();
72 case Constants.LCONST0:
73 case Constants.LCONST1:
74 return long.class.getName();
75 case Constants.FCONST0:
76 case Constants.FCONST1:
77 case Constants.FCONST2:
78 return float.class.getName();
79 case Constants.DCONST0:
80 case Constants.DCONST1:
81 return double.class.getName();
82 }
83
84 Entry entry = getPool().getEntry(_arg);
85 switch (entry.getType()) {
86 case Entry.UTF8:
87 case Entry.STRING:
88 return String.class.getName();
89 case Entry.INT:
90 return int.class.getName();
91 case Entry.FLOAT:
92 return float.class.getName();
93 case Entry.LONG:
94 return long.class.getName();
95 case Entry.DOUBLE:
96 return double.class.getName();
97 case Entry.CLASS:
98 return Class.class.getName();
99 default:
100 return null;
101 }
102 }
103
104 public TypedInstruction setType(String type) {
105 throw new UnsupportedOperationException("Use setValue");
106 }
107
108
109
110
111
112 public Object getValue() {
113 int opcode = getOpcode();
114 switch (opcode) {
115 case Constants.NOP:
116 case Constants.ACONSTNULL:
117 return null;
118 case Constants.ICONSTM1:
119 case Constants.ICONST0:
120 case Constants.ICONST1:
121 case Constants.ICONST2:
122 case Constants.ICONST3:
123 case Constants.ICONST4:
124 case Constants.ICONST5:
125 return Numbers.valueOf(opcode - Constants.ICONST0);
126 case Constants.LCONST0:
127 case Constants.LCONST1:
128 return Numbers.valueOf((long) (opcode - Constants.LCONST0));
129 case Constants.FCONST0:
130 case Constants.FCONST1:
131 case Constants.FCONST2:
132 return new Float(opcode - Constants.FCONST0);
133 case Constants.DCONST0:
134 case Constants.DCONST1:
135 return new Double(opcode - Constants.DCONST0);
136 case Constants.BIPUSH:
137 case Constants.SIPUSH:
138 return Numbers.valueOf(_arg);
139 default:
140 Entry entry = getPool().getEntry(_arg);
141 Object val = ((ConstantEntry) entry).getConstant();
142 if (entry.getType() == Entry.CLASS)
143 return getProject().getNameCache().getExternalForm((String) val,
144 false);
145 return val;
146 }
147 }
148
149
150
151
152
153
154
155
156
157 public ConstantInstruction setValue(Object value) {
158 if (value instanceof Boolean)
159 value = Numbers.valueOf((((Boolean) value).booleanValue()) ? 1 : 0);
160 else if (value instanceof Character)
161 value = Numbers.valueOf((int) ((Character) value).charValue());
162 else if (value instanceof Byte)
163 value = Numbers.valueOf(((Byte) value).intValue());
164 else if (value instanceof Short)
165 value = Numbers.valueOf(((Short) value).intValue());
166 else if ((value != null) && !(value instanceof Number)
167 && !(value instanceof String) && !(value instanceof Class)
168 && !(value instanceof BCClass))
169 throw new IllegalArgumentException("value = " + value);
170
171 calculateOpcode(value, false);
172 return this;
173 }
174
175
176
177
178 public String getStringValue() {
179 return (String) getValue();
180 }
181
182
183
184
185 public int getIntValue() {
186 Object value = getValue();
187 return (value == null) ? 0 : ((Number) value).intValue();
188 }
189
190
191
192
193 public long getLongValue() {
194 Object value = getValue();
195 return (value == null) ? 0L : ((Number) value).longValue();
196 }
197
198
199
200
201 public float getFloatValue() {
202 Object value = getValue();
203 return (value == null) ? 0F : ((Number) value).floatValue();
204 }
205
206
207
208
209 public double getDoubleValue() {
210 Object value = getValue();
211 return (value == null) ? 0D : ((Number) value).doubleValue();
212 }
213
214
215
216
217 public String getClassNameValue() {
218 return (String) getValue();
219 }
220
221
222
223
224
225
226 public ConstantInstruction setNull() {
227 calculateOpcode(null, false);
228 return this;
229 }
230
231
232
233
234
235
236 public ConstantInstruction setValue(String value) {
237 calculateOpcode(value, false);
238 return this;
239 }
240
241
242
243
244
245
246 public ConstantInstruction setValue(Class value) {
247 calculateOpcode(value, false);
248 return this;
249 }
250
251
252
253
254
255
256 public ConstantInstruction setValue(BCClass value) {
257 calculateOpcode(value, false);
258 return this;
259 }
260
261
262
263
264
265
266 public ConstantInstruction setValue(int value) {
267 calculateOpcode(Numbers.valueOf(value), false);
268 return this;
269 }
270
271
272
273
274
275
276 public ConstantInstruction setValue(long value) {
277 calculateOpcode(Numbers.valueOf(value), false);
278 return this;
279 }
280
281
282
283
284
285
286 public ConstantInstruction setValue(float value) {
287 calculateOpcode(new Float(value), false);
288 return this;
289 }
290
291
292
293
294
295
296 public ConstantInstruction setValue(double value) {
297 calculateOpcode(new Double(value), false);
298 return this;
299 }
300
301
302
303
304
305
306 public ConstantInstruction setValue(boolean value) {
307 return setValue((value) ? 1 : 0);
308 }
309
310
311
312
313
314
315 public ConstantInstruction setValue(short value) {
316 return setValue((int) value);
317 }
318
319
320
321
322
323
324 public ConstantInstruction setValue(char value) {
325 return setValue((int) value);
326 }
327
328
329
330
331
332 public boolean equalsInstruction(Instruction other) {
333 if (this == other)
334 return true;
335 if (!(other instanceof ConstantInstruction))
336 return false;
337
338 Object value = getValue();
339 Object otherValue = ((ConstantInstruction) other).getValue();
340 return (value == null) || (otherValue == null)
341 || value.equals(otherValue);
342 }
343
344 public void acceptVisit(BCVisitor visit) {
345 visit.enterConstantInstruction(this);
346 visit.exitConstantInstruction(this);
347 }
348
349 void read(Instruction orig) {
350 super.read(orig);
351 ConstantInstruction ci = (ConstantInstruction) orig;
352 calculateOpcode(ci.getValue(), ci.getOpcode() == Constants.LDCW);
353 }
354
355 void read(DataInput in) throws IOException {
356 super.read(in);
357 switch (getOpcode()) {
358 case Constants.BIPUSH:
359 case Constants.LDC:
360 _arg = in.readUnsignedByte();
361 break;
362 case Constants.SIPUSH:
363 case Constants.LDCW:
364 case Constants.LDC2W:
365 _arg = in.readUnsignedShort();
366 }
367 }
368
369 void write(DataOutput out) throws IOException {
370 super.write(out);
371 switch (getOpcode()) {
372 case Constants.BIPUSH:
373 case Constants.LDC:
374 out.writeByte(_arg);
375 break;
376 case Constants.SIPUSH:
377 case Constants.LDCW:
378 case Constants.LDC2W:
379 out.writeShort(_arg);
380 break;
381 }
382 }
383
384 private void calculateOpcode(Object value, boolean wide) {
385 int len = getLength();
386 _arg = -1;
387 if (value == null)
388 setOpcode(Constants.ACONSTNULL);
389 else if (value instanceof Float) {
390 float floatVal = ((Float) value).floatValue();
391 if ((floatVal == 0) || (floatVal == 1) || (floatVal == 2))
392 setOpcode(Constants.FCONST0 + (int) floatVal);
393 else {
394 _arg = getPool().findFloatEntry((float) floatVal, true);
395 setOpcode((_arg > 255 || wide) ? Constants.LDCW
396 : Constants.LDC);
397 }
398 } else if (value instanceof Long) {
399 long longVal = ((Long) value).longValue();
400 if (longVal == 0 || longVal == 1)
401 setOpcode(Constants.LCONST0 + (int) longVal);
402 else {
403 _arg = getPool().findLongEntry(longVal, true);
404 setOpcode(Constants.LDC2W);
405 }
406 } else if (value instanceof Double) {
407 double doubleVal = ((Double) value).doubleValue();
408 if (doubleVal == 0 || doubleVal == 1)
409 setOpcode(Constants.DCONST0 + (int) doubleVal);
410 else {
411 _arg = getPool().findDoubleEntry(doubleVal, true);
412 setOpcode(Constants.LDC2W);
413 }
414 } else if (value instanceof Integer) {
415 int intVal = ((Integer) value).intValue();
416 if (intVal >= -1 && intVal <= 5)
417 setOpcode(Constants.ICONST0 + intVal);
418 else if ((intVal >= -(2 << 6)) && (intVal < (2 << 6))) {
419 setOpcode(Constants.BIPUSH);
420 _arg = intVal;
421 } else if (intVal >= -(2 << 14) && intVal < (2 << 14)) {
422 setOpcode(Constants.SIPUSH);
423 _arg = intVal;
424 } else {
425 _arg = getPool().findIntEntry(intVal, true);
426 setOpcode((_arg > 255 || wide) ? Constants.LDCW
427 : Constants.LDC);
428 }
429 } else if (value instanceof String) {
430 _arg = getPool().findStringEntry((String) value, true);
431 setOpcode((_arg > 255 || wide) ? Constants.LDCW : Constants.LDC);
432 } else if (value instanceof Class) {
433 String name = getProject().getNameCache().getInternalForm(((Class)
434 value).getName(), false);
435 _arg = getPool().findClassEntry(name, true);
436 setOpcode(Constants.LDCW);
437 } else if (value instanceof BCClass) {
438 BCClass bc = (BCClass) value;
439 ClassEntry entry = (ClassEntry)bc.getPool().getEntry(bc.getIndex());
440 if (bc.getPool() == getPool())
441 _arg = getPool().indexOf(entry);
442 else
443 _arg = getPool().findClassEntry((String) entry.getConstant(),
444 true);
445 setOpcode(Constants.LDCW);
446 } else
447 throw new IllegalArgumentException(String.valueOf(value));
448
449 if (len != getLength())
450 invalidateByteIndexes();
451 }
452 }