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