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.Arrays;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.apache.bcel.Const;
24 import org.apache.bcel.classfile.Constant;
25 import org.apache.bcel.classfile.ConstantCP;
26 import org.apache.bcel.classfile.ConstantClass;
27 import org.apache.bcel.classfile.ConstantDouble;
28 import org.apache.bcel.classfile.ConstantDynamic;
29 import org.apache.bcel.classfile.ConstantFieldref;
30 import org.apache.bcel.classfile.ConstantFloat;
31 import org.apache.bcel.classfile.ConstantInteger;
32 import org.apache.bcel.classfile.ConstantInterfaceMethodref;
33 import org.apache.bcel.classfile.ConstantInvokeDynamic;
34 import org.apache.bcel.classfile.ConstantLong;
35 import org.apache.bcel.classfile.ConstantMethodref;
36 import org.apache.bcel.classfile.ConstantNameAndType;
37 import org.apache.bcel.classfile.ConstantPool;
38 import org.apache.bcel.classfile.ConstantString;
39 import org.apache.bcel.classfile.ConstantUtf8;
40 import org.apache.bcel.classfile.Utility;
41
42
43
44
45
46
47
48
49
50
51 public class ConstantPoolGen {
52
53 private static final int DEFAULT_BUFFER_SIZE = 256;
54
55 private static final String METHODREF_DELIM = ":";
56
57 private static final String IMETHODREF_DELIM = "#";
58
59 private static final String FIELDREF_DELIM = "&";
60
61 private static final String NAT_DELIM = "%";
62
63
64
65
66 @Deprecated
67 protected int size;
68
69
70
71
72 @Deprecated
73 protected Constant[] constants;
74
75
76
77
78 @Deprecated
79 protected int index = 1;
80
81 private final Map<String, Integer> stringTable = new HashMap<>();
82
83 private final Map<String, Integer> classTable = new HashMap<>();
84
85 private final Map<String, Integer> utf8Table = new HashMap<>();
86
87 private final Map<String, Integer> natTable = new HashMap<>();
88
89 private final Map<String, Integer> cpTable = new HashMap<>();
90
91
92
93
94 public ConstantPoolGen() {
95 size = DEFAULT_BUFFER_SIZE;
96 constants = new Constant[size];
97 }
98
99
100
101
102
103
104 public ConstantPoolGen(final Constant[] cs) {
105 final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE);
106
107 size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), Const.MAX_CP_ENTRIES + 1);
108 constants = Arrays.copyOf(cs, size);
109
110 if (cs.length > 0) {
111 index = cs.length;
112 }
113
114 for (int i = 1; i < index; i++) {
115 final Constant c = constants[i];
116 if (c instanceof ConstantString) {
117 final ConstantString s = (ConstantString) c;
118 final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
119 final String key = u8.getBytes();
120 if (!stringTable.containsKey(key)) {
121 stringTable.put(key, Integer.valueOf(i));
122 }
123 } else if (c instanceof ConstantClass) {
124 final ConstantClass s = (ConstantClass) c;
125 final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
126 final String key = u8.getBytes();
127 if (!classTable.containsKey(key)) {
128 classTable.put(key, Integer.valueOf(i));
129 }
130 } else if (c instanceof ConstantNameAndType) {
131 final ConstantNameAndType n = (ConstantNameAndType) c;
132 final ConstantUtf8 u8NameIdx = (ConstantUtf8) constants[n.getNameIndex()];
133 final ConstantUtf8 u8SigIdx = (ConstantUtf8) constants[n.getSignatureIndex()];
134
135 sb.append(u8NameIdx.getBytes());
136 sb.append(NAT_DELIM);
137 sb.append(u8SigIdx.getBytes());
138 final String key = sb.toString();
139 sb.delete(0, sb.length());
140
141 if (!natTable.containsKey(key)) {
142 natTable.put(key, Integer.valueOf(i));
143 }
144 } else if (c instanceof ConstantUtf8) {
145 final ConstantUtf8 u = (ConstantUtf8) c;
146 final String key = u.getBytes();
147 if (!utf8Table.containsKey(key)) {
148 utf8Table.put(key, Integer.valueOf(i));
149 }
150 } else if (c instanceof ConstantCP) {
151 final ConstantCP m = (ConstantCP) c;
152 String className;
153 ConstantUtf8 u8;
154
155 if (c instanceof ConstantInvokeDynamic) {
156 className = Integer.toString(((ConstantInvokeDynamic) m).getBootstrapMethodAttrIndex());
157 } else if (c instanceof ConstantDynamic) {
158 className = Integer.toString(((ConstantDynamic) m).getBootstrapMethodAttrIndex());
159 } else {
160 final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
161 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
162 className = Utility.pathToPackage(u8.getBytes());
163 }
164
165 final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
166 u8 = (ConstantUtf8) constants[n.getNameIndex()];
167 final String methodName = u8.getBytes();
168 u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
169 final String signature = u8.getBytes();
170
171
172 String delim = METHODREF_DELIM;
173 if (c instanceof ConstantInterfaceMethodref) {
174 delim = IMETHODREF_DELIM;
175 } else if (c instanceof ConstantFieldref) {
176 delim = FIELDREF_DELIM;
177 }
178
179 sb.append(className);
180 sb.append(delim);
181 sb.append(methodName);
182 sb.append(delim);
183 sb.append(signature);
184 final String key = sb.toString();
185 sb.delete(0, sb.length());
186
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
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 }