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