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