1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.bcel.generic;
18
19 import java.util.HashMap;
20 import java.util.Map;
21 import org.apache.bcel.Constants;
22 import org.apache.bcel.classfile.Constant;
23 import org.apache.bcel.classfile.ConstantCP;
24 import org.apache.bcel.classfile.ConstantClass;
25 import org.apache.bcel.classfile.ConstantDouble;
26 import org.apache.bcel.classfile.ConstantFieldref;
27 import org.apache.bcel.classfile.ConstantFloat;
28 import org.apache.bcel.classfile.ConstantInteger;
29 import org.apache.bcel.classfile.ConstantInterfaceMethodref;
30 import org.apache.bcel.classfile.ConstantLong;
31 import org.apache.bcel.classfile.ConstantMethodref;
32 import org.apache.bcel.classfile.ConstantNameAndType;
33 import org.apache.bcel.classfile.ConstantPool;
34 import org.apache.bcel.classfile.ConstantString;
35 import org.apache.bcel.classfile.ConstantUtf8;
36
37 /***
38 * This class is used to build up a constant pool. The user adds
39 * constants via `addXXX' methods, `addString', `addClass',
40 * etc.. These methods return an index into the constant
41 * pool. Finally, `getFinalConstantPool()' returns the constant pool
42 * built up. Intermediate versions of the constant pool can be
43 * obtained with `getConstantPool()'. A constant pool has capacity for
44 * Constants.MAX_SHORT entries. Note that the first (0) is used by the
45 * JVM and that Double and Long constants need two slots.
46 *
47 * @version $Id: ConstantPoolGen.java 386056 2006-03-15 11:31:56Z tcurdt $
48 * @author <A HREF="mailto:m.dahm@gmx.de">M. Dahm</A>
49 * @see Constant
50 */
51 public class ConstantPoolGen implements java.io.Serializable {
52
53 protected int size = 1024;
54 protected Constant[] constants = new Constant[size];
55 protected int index = 1;
56 private static final String METHODREF_DELIM = ":";
57 private static final String IMETHODREF_DELIM = "#";
58 private static final String FIELDREF_DELIM = "&";
59 private static final String NAT_DELIM = "%";
60
61 private static class Index implements java.io.Serializable {
62
63 int index;
64
65
66 Index(int i) {
67 index = i;
68 }
69 }
70
71
72 /***
73 * Initialize with given array of constants.
74 *
75 * @param cs array of given constants, new ones will be appended
76 */
77 public ConstantPoolGen(Constant[] cs) {
78 if (cs.length > size) {
79 size = cs.length;
80 constants = new Constant[size];
81 }
82 System.arraycopy(cs, 0, constants, 0, cs.length);
83 if (cs.length > 0) {
84 index = cs.length;
85 }
86 for (int i = 1; i < index; i++) {
87 Constant c = constants[i];
88 if (c instanceof ConstantString) {
89 ConstantString s = (ConstantString) c;
90 ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
91 String key = u8.getBytes();
92 if (!string_table.containsKey(key)) {
93 string_table.put(key, new Index(i));
94 }
95 } else if (c instanceof ConstantClass) {
96 ConstantClass s = (ConstantClass) c;
97 ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
98 String key = u8.getBytes();
99 if (!class_table.containsKey(key)) {
100 class_table.put(key, new Index(i));
101 }
102 } else if (c instanceof ConstantNameAndType) {
103 ConstantNameAndType n = (ConstantNameAndType) c;
104 ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
105 ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
106 String key = u8.getBytes() + NAT_DELIM + u8_2.getBytes();
107 if (!n_a_t_table.containsKey(key)) {
108 n_a_t_table.put(key, new Index(i));
109 }
110 } else if (c instanceof ConstantUtf8) {
111 ConstantUtf8 u = (ConstantUtf8) c;
112 String key = u.getBytes();
113 if (!utf8_table.containsKey(key)) {
114 utf8_table.put(key, new Index(i));
115 }
116 } else if (c instanceof ConstantCP) {
117 ConstantCP m = (ConstantCP) c;
118 ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
119 ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
120 ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
121 String class_name = u8.getBytes().replace('/', '.');
122 u8 = (ConstantUtf8) constants[n.getNameIndex()];
123 String method_name = u8.getBytes();
124 u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
125 String signature = u8.getBytes();
126 String delim = METHODREF_DELIM;
127 if (c instanceof ConstantInterfaceMethodref) {
128 delim = IMETHODREF_DELIM;
129 } else if (c instanceof ConstantFieldref) {
130 delim = FIELDREF_DELIM;
131 }
132 String key = class_name + delim + method_name + delim + signature;
133 if (!cp_table.containsKey(key)) {
134 cp_table.put(key, new Index(i));
135 }
136 }
137 }
138 }
139
140
141 /***
142 * Initialize with given constant pool.
143 */
144 public ConstantPoolGen(ConstantPool cp) {
145 this(cp.getConstantPool());
146 }
147
148
149 /***
150 * Create empty constant pool.
151 */
152 public ConstantPoolGen() {
153 }
154
155
156 /*** Resize internal array of constants.
157 */
158 protected void adjustSize() {
159 if (index + 3 >= size) {
160 Constant[] cs = constants;
161 size *= 2;
162 constants = new Constant[size];
163 System.arraycopy(cs, 0, constants, 0, index);
164 }
165 }
166
167 private Map string_table = new HashMap();
168
169
170 /***
171 * Look for ConstantString in ConstantPool containing String `str'.
172 *
173 * @param str String to search for
174 * @return index on success, -1 otherwise
175 */
176 public int lookupString( String str ) {
177 Index index = (Index) string_table.get(str);
178 return (index != null) ? index.index : -1;
179 }
180
181
182 /***
183 * Add a new String constant to the ConstantPool, if it is not already in there.
184 *
185 * @param str String to add
186 * @return index of entry
187 */
188 public int addString( String str ) {
189 int ret;
190 if ((ret = lookupString(str)) != -1) {
191 return ret;
192 }
193 int utf8 = addUtf8(str);
194 adjustSize();
195 ConstantString s = new ConstantString(utf8);
196 ret = index;
197 constants[index++] = s;
198 if (!string_table.containsKey(str)) {
199 string_table.put(str, new Index(ret));
200 }
201 return ret;
202 }
203
204 private Map class_table = new HashMap();
205
206
207 /***
208 * Look for ConstantClass in ConstantPool named `str'.
209 *
210 * @param str String to search for
211 * @return index on success, -1 otherwise
212 */
213 public int lookupClass( String str ) {
214 Index index = (Index) class_table.get(str.replace('.', '/'));
215 return (index != null) ? index.index : -1;
216 }
217
218
219 private int addClass_( String clazz ) {
220 int ret;
221 if ((ret = lookupClass(clazz)) != -1) {
222 return ret;
223 }
224 adjustSize();
225 ConstantClass c = new ConstantClass(addUtf8(clazz));
226 ret = index;
227 constants[index++] = c;
228 if (!class_table.containsKey(clazz)) {
229 class_table.put(clazz, new Index(ret));
230 }
231 return ret;
232 }
233
234
235 /***
236 * Add a new Class reference to the ConstantPool, if it is not already in there.
237 *
238 * @param str Class to add
239 * @return index of entry
240 */
241 public int addClass( String str ) {
242 return addClass_(str.replace('.', '/'));
243 }
244
245
246 /***
247 * Add a new Class reference to the ConstantPool for a given type.
248 *
249 * @param type Class to add
250 * @return index of entry
251 */
252 public int addClass( ObjectType type ) {
253 return addClass(type.getClassName());
254 }
255
256
257 /***
258 * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY
259 * instruction, e.g. to the ConstantPool.
260 *
261 * @param type type of array class
262 * @return index of entry
263 */
264 public int addArrayClass( ArrayType type ) {
265 return addClass_(type.getSignature());
266 }
267
268
269 /***
270 * Look for ConstantInteger in ConstantPool.
271 *
272 * @param n integer number to look for
273 * @return index on success, -1 otherwise
274 */
275 public int lookupInteger( int n ) {
276 for (int i = 1; i < index; i++) {
277 if (constants[i] instanceof ConstantInteger) {
278 ConstantInteger c = (ConstantInteger) constants[i];
279 if (c.getBytes() == n) {
280 return i;
281 }
282 }
283 }
284 return -1;
285 }
286
287
288 /***
289 * Add a new Integer constant to the ConstantPool, if it is not already in there.
290 *
291 * @param n integer number to add
292 * @return index of entry
293 */
294 public int addInteger( int n ) {
295 int ret;
296 if ((ret = lookupInteger(n)) != -1) {
297 return ret;
298 }
299 adjustSize();
300 ret = index;
301 constants[index++] = new ConstantInteger(n);
302 return ret;
303 }
304
305
306 /***
307 * Look for ConstantFloat in ConstantPool.
308 *
309 * @param n Float number to look for
310 * @return index on success, -1 otherwise
311 */
312 public int lookupFloat( float n ) {
313 int bits = Float.floatToIntBits(n);
314 for (int i = 1; i < index; i++) {
315 if (constants[i] instanceof ConstantFloat) {
316 ConstantFloat c = (ConstantFloat) constants[i];
317 if (Float.floatToIntBits(c.getBytes()) == bits) {
318 return i;
319 }
320 }
321 }
322 return -1;
323 }
324
325
326 /***
327 * Add a new Float constant to the ConstantPool, if it is not already in there.
328 *
329 * @param n Float number to add
330 * @return index of entry
331 */
332 public int addFloat( float n ) {
333 int ret;
334 if ((ret = lookupFloat(n)) != -1) {
335 return ret;
336 }
337 adjustSize();
338 ret = index;
339 constants[index++] = new ConstantFloat(n);
340 return ret;
341 }
342
343 private Map utf8_table = new HashMap();
344
345
346 /***
347 * Look for ConstantUtf8 in ConstantPool.
348 *
349 * @param n Utf8 string to look for
350 * @return index on success, -1 otherwise
351 */
352 public int lookupUtf8( String n ) {
353 Index index = (Index) utf8_table.get(n);
354 return (index != null) ? index.index : -1;
355 }
356
357
358 /***
359 * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
360 *
361 * @param n Utf8 string to add
362 * @return index of entry
363 */
364 public int addUtf8( String n ) {
365 int ret;
366 if ((ret = lookupUtf8(n)) != -1) {
367 return ret;
368 }
369 adjustSize();
370 ret = index;
371 constants[index++] = new ConstantUtf8(n);
372 if (!utf8_table.containsKey(n)) {
373 utf8_table.put(n, new Index(ret));
374 }
375 return ret;
376 }
377
378
379 /***
380 * Look for ConstantLong in ConstantPool.
381 *
382 * @param n Long number to look for
383 * @return index on success, -1 otherwise
384 */
385 public int lookupLong( long n ) {
386 for (int i = 1; i < index; i++) {
387 if (constants[i] instanceof ConstantLong) {
388 ConstantLong c = (ConstantLong) constants[i];
389 if (c.getBytes() == n) {
390 return i;
391 }
392 }
393 }
394 return -1;
395 }
396
397
398 /***
399 * Add a new long constant to the ConstantPool, if it is not already in there.
400 *
401 * @param n Long number to add
402 * @return index of entry
403 */
404 public int addLong( long n ) {
405 int ret;
406 if ((ret = lookupLong(n)) != -1) {
407 return ret;
408 }
409 adjustSize();
410 ret = index;
411 constants[index] = new ConstantLong(n);
412 index += 2;
413 return ret;
414 }
415
416
417 /***
418 * Look for ConstantDouble in ConstantPool.
419 *
420 * @param n Double number to look for
421 * @return index on success, -1 otherwise
422 */
423 public int lookupDouble( double n ) {
424 long bits = Double.doubleToLongBits(n);
425 for (int i = 1; i < index; i++) {
426 if (constants[i] instanceof ConstantDouble) {
427 ConstantDouble c = (ConstantDouble) constants[i];
428 if (Double.doubleToLongBits(c.getBytes()) == bits) {
429 return i;
430 }
431 }
432 }
433 return -1;
434 }
435
436
437 /***
438 * Add a new double constant to the ConstantPool, if it is not already in there.
439 *
440 * @param n Double number to add
441 * @return index of entry
442 */
443 public int addDouble( double n ) {
444 int ret;
445 if ((ret = lookupDouble(n)) != -1) {
446 return ret;
447 }
448 adjustSize();
449 ret = index;
450 constants[index] = new ConstantDouble(n);
451 index += 2;
452 return ret;
453 }
454
455 private Map n_a_t_table = new HashMap();
456
457
458 /***
459 * Look for ConstantNameAndType in ConstantPool.
460 *
461 * @param name of variable/method
462 * @param signature of variable/method
463 * @return index on success, -1 otherwise
464 */
465 public int lookupNameAndType( String name, String signature ) {
466 Index _index = (Index) n_a_t_table.get(name + NAT_DELIM + signature);
467 return (_index != null) ? _index.index : -1;
468 }
469
470
471 /***
472 * Add a new NameAndType constant to the ConstantPool if it is not already
473 * in there.
474 *
475 * @param name Name string to add
476 * @param signature signature string to add
477 * @return index of entry
478 */
479 public int addNameAndType( String name, String signature ) {
480 int ret;
481 int name_index, signature_index;
482 if ((ret = lookupNameAndType(name, signature)) != -1) {
483 return ret;
484 }
485 adjustSize();
486 name_index = addUtf8(name);
487 signature_index = addUtf8(signature);
488 ret = index;
489 constants[index++] = new ConstantNameAndType(name_index, signature_index);
490 String key = name + NAT_DELIM + signature;
491 if (!n_a_t_table.containsKey(key)) {
492 n_a_t_table.put(key, new Index(ret));
493 }
494 return ret;
495 }
496
497 private Map cp_table = new HashMap();
498
499
500 /***
501 * Look for ConstantMethodref in ConstantPool.
502 *
503 * @param class_name Where to find method
504 * @param method_name Guess what
505 * @param signature return and argument types
506 * @return index on success, -1 otherwise
507 */
508 public int lookupMethodref( String class_name, String method_name, String signature ) {
509 Index index = (Index) cp_table.get(class_name + METHODREF_DELIM + method_name
510 + METHODREF_DELIM + signature);
511 return (index != null) ? index.index : -1;
512 }
513
514
515 public int lookupMethodref( MethodGen method ) {
516 return lookupMethodref(method.getClassName(), method.getName(), method.getSignature());
517 }
518
519
520 /***
521 * Add a new Methodref constant to the ConstantPool, if it is not already
522 * in there.
523 *
524 * @param class_name class name string to add
525 * @param method_name method name string to add
526 * @param signature method signature string to add
527 * @return index of entry
528 */
529 public int addMethodref( String class_name, String method_name, String signature ) {
530 int ret, class_index, name_and_type_index;
531 if ((ret = lookupMethodref(class_name, method_name, signature)) != -1) {
532 return ret;
533 }
534 adjustSize();
535 name_and_type_index = addNameAndType(method_name, signature);
536 class_index = addClass(class_name);
537 ret = index;
538 constants[index++] = new ConstantMethodref(class_index, name_and_type_index);
539 String key = class_name + METHODREF_DELIM + method_name + METHODREF_DELIM + signature;
540 if (!cp_table.containsKey(key)) {
541 cp_table.put(key, new Index(ret));
542 }
543 return ret;
544 }
545
546
547 public int addMethodref( MethodGen method ) {
548 return addMethodref(method.getClassName(), method.getName(), method.getSignature());
549 }
550
551
552 /***
553 * Look for ConstantInterfaceMethodref in ConstantPool.
554 *
555 * @param class_name Where to find method
556 * @param method_name Guess what
557 * @param signature return and argument types
558 * @return index on success, -1 otherwise
559 */
560 public int lookupInterfaceMethodref( String class_name, String method_name, String signature ) {
561 Index index = (Index) cp_table.get(class_name + IMETHODREF_DELIM + method_name
562 + IMETHODREF_DELIM + signature);
563 return (index != null) ? index.index : -1;
564 }
565
566
567 public int lookupInterfaceMethodref( MethodGen method ) {
568 return lookupInterfaceMethodref(method.getClassName(), method.getName(), method
569 .getSignature());
570 }
571
572
573 /***
574 * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already
575 * in there.
576 *
577 * @param class_name class name string to add
578 * @param method_name method name string to add
579 * @param signature signature string to add
580 * @return index of entry
581 */
582 public int addInterfaceMethodref( String class_name, String method_name, String signature ) {
583 int ret, class_index, name_and_type_index;
584 if ((ret = lookupInterfaceMethodref(class_name, method_name, signature)) != -1) {
585 return ret;
586 }
587 adjustSize();
588 class_index = addClass(class_name);
589 name_and_type_index = addNameAndType(method_name, signature);
590 ret = index;
591 constants[index++] = new ConstantInterfaceMethodref(class_index, name_and_type_index);
592 String key = class_name + IMETHODREF_DELIM + method_name + IMETHODREF_DELIM + signature;
593 if (!cp_table.containsKey(key)) {
594 cp_table.put(key, new Index(ret));
595 }
596 return ret;
597 }
598
599
600 public int addInterfaceMethodref( MethodGen method ) {
601 return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
602 }
603
604
605 /***
606 * Look for ConstantFieldref in ConstantPool.
607 *
608 * @param class_name Where to find method
609 * @param field_name Guess what
610 * @param signature return and argument types
611 * @return index on success, -1 otherwise
612 */
613 public int lookupFieldref( String class_name, String field_name, String signature ) {
614 Index index = (Index) cp_table.get(class_name + FIELDREF_DELIM + field_name
615 + FIELDREF_DELIM + signature);
616 return (index != null) ? index.index : -1;
617 }
618
619
620 /***
621 * Add a new Fieldref constant to the ConstantPool, if it is not already
622 * in there.
623 *
624 * @param class_name class name string to add
625 * @param field_name field name string to add
626 * @param signature signature string to add
627 * @return index of entry
628 */
629 public int addFieldref( String class_name, String field_name, String signature ) {
630 int ret;
631 int class_index, name_and_type_index;
632 if ((ret = lookupFieldref(class_name, field_name, signature)) != -1) {
633 return ret;
634 }
635 adjustSize();
636 class_index = addClass(class_name);
637 name_and_type_index = addNameAndType(field_name, signature);
638 ret = index;
639 constants[index++] = new ConstantFieldref(class_index, name_and_type_index);
640 String key = class_name + FIELDREF_DELIM + field_name + FIELDREF_DELIM + signature;
641 if (!cp_table.containsKey(key)) {
642 cp_table.put(key, new Index(ret));
643 }
644 return ret;
645 }
646
647
648 /***
649 * @param i index in constant pool
650 * @return constant pool entry at index i
651 */
652 public Constant getConstant( int i ) {
653 return constants[i];
654 }
655
656
657 /***
658 * Use with care!
659 *
660 * @param i index in constant pool
661 * @param c new constant pool entry at index i
662 */
663 public void setConstant( int i, Constant c ) {
664 constants[i] = c;
665 }
666
667
668 /***
669 * @return intermediate constant pool
670 */
671 public ConstantPool getConstantPool() {
672 return new ConstantPool(constants);
673 }
674
675
676 /***
677 * @return current size of constant pool
678 */
679 public int getSize() {
680 return index;
681 }
682
683
684 /***
685 * @return constant pool with proper length
686 */
687 public ConstantPool getFinalConstantPool() {
688 Constant[] cs = new Constant[index];
689 System.arraycopy(constants, 0, cs, 0, index);
690 return new ConstantPool(cs);
691 }
692
693
694 /***
695 * @return String representation.
696 */
697 public String toString() {
698 StringBuffer buf = new StringBuffer();
699 for (int i = 1; i < index; i++) {
700 buf.append(i).append(")").append(constants[i]).append("\n");
701 }
702 return buf.toString();
703 }
704
705
706 /*** Import constant from another ConstantPool and return new index.
707 */
708 public int addConstant( Constant c, ConstantPoolGen cp ) {
709 Constant[] constants = cp.getConstantPool().getConstantPool();
710 switch (c.getTag()) {
711 case Constants.CONSTANT_String: {
712 ConstantString s = (ConstantString) c;
713 ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
714 return addString(u8.getBytes());
715 }
716 case Constants.CONSTANT_Class: {
717 ConstantClass s = (ConstantClass) c;
718 ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
719 return addClass(u8.getBytes());
720 }
721 case Constants.CONSTANT_NameAndType: {
722 ConstantNameAndType n = (ConstantNameAndType) c;
723 ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
724 ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
725 return addNameAndType(u8.getBytes(), u8_2.getBytes());
726 }
727 case Constants.CONSTANT_Utf8:
728 return addUtf8(((ConstantUtf8) c).getBytes());
729 case Constants.CONSTANT_Double:
730 return addDouble(((ConstantDouble) c).getBytes());
731 case Constants.CONSTANT_Float:
732 return addFloat(((ConstantFloat) c).getBytes());
733 case Constants.CONSTANT_Long:
734 return addLong(((ConstantLong) c).getBytes());
735 case Constants.CONSTANT_Integer:
736 return addInteger(((ConstantInteger) c).getBytes());
737 case Constants.CONSTANT_InterfaceMethodref:
738 case Constants.CONSTANT_Methodref:
739 case Constants.CONSTANT_Fieldref: {
740 ConstantCP m = (ConstantCP) c;
741 ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
742 ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
743 ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
744 String class_name = u8.getBytes().replace('/', '.');
745 u8 = (ConstantUtf8) constants[n.getNameIndex()];
746 String name = u8.getBytes();
747 u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
748 String signature = u8.getBytes();
749 switch (c.getTag()) {
750 case Constants.CONSTANT_InterfaceMethodref:
751 return addInterfaceMethodref(class_name, name, signature);
752 case Constants.CONSTANT_Methodref:
753 return addMethodref(class_name, name, signature);
754 case Constants.CONSTANT_Fieldref:
755 return addFieldref(class_name, name, signature);
756 default:
757 throw new RuntimeException("Unknown constant type " + c);
758 }
759 }
760 default:
761 throw new RuntimeException("Unknown constant type " + c);
762 }
763 }
764 }