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