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 public int addInterfaceMethodref(final MethodGen method) {
406 return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
407 }
408
409
410
411
412
413
414
415
416
417 public int addInterfaceMethodref(final String className, final String methodName, final String signature) {
418 final int cpRet;
419 if ((cpRet = lookupInterfaceMethodref(className, methodName, signature)) != -1) {
420 return cpRet;
421 }
422 adjustSize();
423 final int classIndex = addClass(className);
424 final int nameAndTypeIndex = addNameAndType(methodName, signature);
425 final int ret = index;
426 constants[index++] = new ConstantInterfaceMethodref(classIndex, nameAndTypeIndex);
427 return computeIfAbsent(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature, ret);
428 }
429
430
431
432
433
434
435
436 public int addLong(final long n) {
437 int ret;
438 if ((ret = lookupLong(n)) != -1) {
439 return ret;
440 }
441 adjustSize();
442 ret = index;
443 constants[index] = new ConstantLong(n);
444 index += 2;
445 return ret;
446 }
447 public int addMethodref(final MethodGen method) {
448 return addMethodref(method.getClassName(), method.getName(), method.getSignature());
449 }
450
451
452
453
454
455
456
457
458
459 public int addMethodref(final String className, final String methodName, final String signature) {
460 final int cpRet;
461 if ((cpRet = lookupMethodref(className, methodName, signature)) != -1) {
462 return cpRet;
463 }
464 adjustSize();
465 final int nameAndTypeIndex = addNameAndType(methodName, signature);
466 final int classIndex = addClass(className);
467 final int ret = index;
468 constants[index++] = new ConstantMethodref(classIndex, nameAndTypeIndex);
469 return computeIfAbsent(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature, ret);
470 }
471
472
473
474
475
476
477
478
479 public int addNameAndType(final String name, final String signature) {
480 int ret;
481 if ((ret = lookupNameAndType(name, signature)) != -1) {
482 return ret;
483 }
484 adjustSize();
485 final int nameIndex = addUtf8(name);
486 final int signatureIndex = addUtf8(signature);
487 ret = index;
488 constants[index++] = new ConstantNameAndType(nameIndex, signatureIndex);
489 return computeIfAbsent(natTable, name + NAT_DELIM + signature, ret);
490 }
491
492
493
494
495
496
497
498 public int addString(final String str) {
499 int ret;
500 if ((ret = lookupString(str)) != -1) {
501 return ret;
502 }
503 final int utf8 = addUtf8(str);
504 adjustSize();
505 final ConstantString s = new ConstantString(utf8);
506 ret = index;
507 constants[index++] = s;
508 return computeIfAbsent(stringTable, str, ret);
509 }
510
511
512
513
514
515
516
517 public int addUtf8(final String n) {
518 int ret;
519 if ((ret = lookupUtf8(n)) != -1) {
520 return ret;
521 }
522 adjustSize();
523 ret = index;
524 constants[index++] = new ConstantUtf8(n);
525 return computeIfAbsent(utf8Table, n, ret);
526 }
527
528
529
530
531 protected void adjustSize() {
532
533 if (index + 3 >= Const.MAX_CP_ENTRIES + 1) {
534 throw new IllegalStateException("The number of constants " + (index + 3)
535 + " is over the size of the constant pool: "
536 + Const.MAX_CP_ENTRIES);
537 }
538
539 if (index + 3 >= size) {
540 final Constant[] tmp = constants;
541 size *= 2;
542
543 size = Math.min(size, Const.MAX_CP_ENTRIES + 1);
544 constants = new Constant[size];
545 System.arraycopy(tmp, 0, constants, 0, index);
546 }
547 }
548
549 private int computeIfAbsent(final Map<String, Integer> map, final String key, final int value) {
550 return map.computeIfAbsent(key, k -> Integer.valueOf(value));
551 }
552
553
554
555
556
557 public Constant getConstant(final int i) {
558 return constants[i];
559 }
560
561
562
563
564 public ConstantPool getConstantPool() {
565 return new ConstantPool(constants);
566 }
567
568
569
570
571 public ConstantPool getFinalConstantPool() {
572 return new ConstantPool(Arrays.copyOf(constants, index));
573 }
574
575 private int getIndex(final Map<String, Integer> map, final String key) {
576 return toIndex(map.get(key));
577 }
578
579
580
581
582 public int getSize() {
583 return index;
584 }
585
586
587
588
589
590
591
592 public int lookupClass(final String str) {
593 return getIndex(classTable, Utility.packageToPath(str));
594 }
595
596
597
598
599
600
601
602 public int lookupDouble(final double n) {
603 final long bits = Double.doubleToLongBits(n);
604 for (int i = 1; i < index; i++) {
605 if (constants[i] instanceof ConstantDouble) {
606 final ConstantDouble c = (ConstantDouble) constants[i];
607 if (Double.doubleToLongBits(c.getBytes()) == bits) {
608 return i;
609 }
610 }
611 }
612 return -1;
613 }
614
615
616
617
618
619
620
621
622
623 public int lookupFieldref(final String className, final String fieldName, final String signature) {
624 return getIndex(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature);
625 }
626
627
628
629
630
631
632
633 public int lookupFloat(final float n) {
634 final int bits = Float.floatToIntBits(n);
635 for (int i = 1; i < index; i++) {
636 if (constants[i] instanceof ConstantFloat) {
637 final ConstantFloat c = (ConstantFloat) constants[i];
638 if (Float.floatToIntBits(c.getBytes()) == bits) {
639 return i;
640 }
641 }
642 }
643 return -1;
644 }
645
646
647
648
649
650
651
652 public int lookupInteger(final int n) {
653 for (int i = 1; i < index; i++) {
654 if (constants[i] instanceof ConstantInteger) {
655 final ConstantInteger c = (ConstantInteger) constants[i];
656 if (c.getBytes() == n) {
657 return i;
658 }
659 }
660 }
661 return -1;
662 }
663
664 public int lookupInterfaceMethodref(final MethodGen method) {
665 return lookupInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
666 }
667
668
669
670
671
672
673
674
675
676 public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) {
677 return getIndex(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature);
678 }
679
680
681
682
683
684
685
686 public int lookupLong(final long n) {
687 for (int i = 1; i < index; i++) {
688 if (constants[i] instanceof ConstantLong) {
689 final ConstantLong c = (ConstantLong) constants[i];
690 if (c.getBytes() == n) {
691 return i;
692 }
693 }
694 }
695 return -1;
696 }
697
698 public int lookupMethodref(final MethodGen method) {
699 return lookupMethodref(method.getClassName(), method.getName(), method.getSignature());
700 }
701
702
703
704
705
706
707
708
709
710 public int lookupMethodref(final String className, final String methodName, final String signature) {
711 return getIndex(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature);
712 }
713
714
715
716
717
718
719
720
721 public int lookupNameAndType(final String name, final String signature) {
722 return getIndex(natTable, name + NAT_DELIM + signature);
723 }
724
725
726
727
728
729
730
731 public int lookupString(final String str) {
732 return getIndex(stringTable, str);
733 }
734
735
736
737
738
739
740
741 public int lookupUtf8(final String n) {
742 return getIndex(utf8Table, n);
743 }
744
745
746
747
748
749
750
751 public void setConstant(final int i, final Constant c) {
752 constants[i] = c;
753 }
754
755 private int toIndex(final Integer index) {
756 return index != null ? index.intValue() : -1;
757 }
758
759
760
761
762 @Override
763 public String toString() {
764 final StringBuilder buf = new StringBuilder();
765 for (int i = 1; i < index; i++) {
766 buf.append(i).append(")").append(constants[i]).append("\n");
767 }
768 return buf.toString();
769 }
770 }