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