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