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