    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 *  Unless required by applicable law or agreed to in writing, software
    012 *  distributed under the License is distributed on an "AS IS" BASIS,
    013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 *  See the License for the specific language governing permissions and
    015 *  limitations under the License.
    016 *
    017 */
    018package org.apache.bcel.generic;
    019
    020import java.util.HashMap;
    021import java.util.Map;
    022
    023import org.apache.bcel.Const;
    024import org.apache.bcel.classfile.Constant;
    025import org.apache.bcel.classfile.ConstantCP;
    026import org.apache.bcel.classfile.ConstantClass;
    027import org.apache.bcel.classfile.ConstantDouble;
    028import org.apache.bcel.classfile.ConstantFieldref;
    029import org.apache.bcel.classfile.ConstantFloat;
    030import org.apache.bcel.classfile.ConstantInteger;
    031import org.apache.bcel.classfile.ConstantInterfaceMethodref;
    032import org.apache.bcel.classfile.ConstantInvokeDynamic;
    033import org.apache.bcel.classfile.ConstantLong;
    034import org.apache.bcel.classfile.ConstantMethodref;
    035import org.apache.bcel.classfile.ConstantNameAndType;
    036import org.apache.bcel.classfile.ConstantPool;
    037import org.apache.bcel.classfile.ConstantString;
    038import org.apache.bcel.classfile.ConstantUtf8;
    039
    040/**
    041 * This class is used to build up a constant pool. The user adds
    042 * constants via `addXXX' methods, `addString', `addClass',
    043 * etc.. These methods return an index into the constant
    044 * pool. Finally, `getFinalConstantPool()' returns the constant pool
    045 * built up. Intermediate versions of the constant pool can be
    046 * obtained with `getConstantPool()'. A constant pool has capacity for
    047 * Constants.MAX_SHORT entries. Note that the first (0) is used by the
    048 * JVM and that Double and Long constants need two slots.
    049 *
    050 * @version $Id: ConstantPoolGen.java 1806200 2017-08-25 16:33:06Z ggregory $
    051 * @see Constant
    052 */
    053public class ConstantPoolGen {
    054
    055    private static final int DEFAULT_BUFFER_SIZE = 256;
    056
    057    /**
    058     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    059     */
    060    @Deprecated
    061    protected int size;
    062
    063    /**
    064     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    065     */
    066    @Deprecated
    067    protected Constant[] constants;
    068
    069    /**
    070     * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
    071     */
    072    @Deprecated
    073    protected int index = 1; // First entry (0) used by JVM
    074
    075    private static final String METHODREF_DELIM = ":";
    076    private static final String IMETHODREF_DELIM = "#";
    077    private static final String FIELDREF_DELIM = "&";
    078    private static final String NAT_DELIM = "%"; // Name and Type
    079
    080    private static class Index {
    081
    082        final int index;
    083
    084
    085        Index(final int i) {
    086            index = i;
    087        }
    088    }
    089
    090
    091    /**
    092     * Initialize with given array of constants.
    093     *
    094     * @param cs array of given constants, new ones will be appended
    095     */
    096    public ConstantPoolGen(final Constant[] cs) {
    097        final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE);
    098
    099        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}