    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 */
    017package org.apache.bcel.generic;
    018
    019import java.util.Arrays;
    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 final int DEFAULT_BUFFER_SIZE = 256;
    054
    055    private static final String METHODREF_DELIM = ":";
    056
    057    private static final String IMETHODREF_DELIM = "#";
    058
    059    private static final String FIELDREF_DELIM = "&";
    060
    061    private static final String NAT_DELIM = "%"; // Name and Type
    062
    063    /**
    064     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    065     */
    066    @Deprecated
    067    protected int size;
    068
    069    /**
    070     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
    071     */
    072    @Deprecated
    073    protected Constant[] constants;
    074
    075    /**
    076     * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
    077     */
    078    @Deprecated
    079    protected int index = 1; // First entry (0) used by JVM
    080
    081    private final Map<String, Integer> stringTable = new HashMap<>();
    082
    083    private final Map<String, Integer> classTable = new HashMap<>();
    084
    085    private final Map<String, Integer> utf8Table = new HashMap<>();
    086
    087    private final Map<String, Integer> natTable = new HashMap<>();
    088
    089    private final Map<String, Integer> cpTable = new HashMap<>();
    090
    091    /**
    092     * Constructs a new empty constant pool.
    093     */
    094    public ConstantPoolGen() {
    095        size = DEFAULT_BUFFER_SIZE;
    096        constants = new Constant[size];
    097    }
    098
    099    /**
    100     * Constructs a new instance with the given array of constants.
    101     *
    102     * @param cs array of given constants, new ones will be appended
    103     */
    104    public ConstantPoolGen(final Constant[] cs) {
    105        final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE);
    106
    107        size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), Const.MAX_CP_ENTRIES + 1);
    108        constants = Arrays.copyOf(cs, size);
    109
    110        if (cs.length > 0) {
    111            index = cs.length;
    112        }
    113
    114        for (int i = 1; i < index; i++) {
    115            final Constant c = constants[i];
    116            if (c instanceof ConstantString) {
    117                final ConstantString s = (ConstantString) c;
    118                final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
    119                final String key = u8.getBytes();
    120                if (!stringTable.containsKey(key)) {
    121                    stringTable.put(key, Integer.valueOf(i));
    122                }
    123            } else if (c instanceof ConstantClass) {
    124                final ConstantClass s = (ConstantClass) c;
    125                final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
    126                final String key = u8.getBytes();
    127                if (!classTable.containsKey(key)) {
    128                    classTable.put(key, Integer.valueOf(i));
    129                }
    130            } else if (c instanceof ConstantNameAndType) {
    131                final ConstantNameAndType n = (ConstantNameAndType) c;
    132                final ConstantUtf8 u8NameIdx = (ConstantUtf8) constants[n.getNameIndex()];
    133                final ConstantUtf8 u8SigIdx = (ConstantUtf8) constants[n.getSignatureIndex()];
    134
    135                sb.append(u8NameIdx.getBytes());
    136                sb.append(NAT_DELIM);
    137                sb.append(u8SigIdx.getBytes());
    138                final String key = sb.toString();
    139                sb.delete(0, sb.length());
    140
    141                if (!natTable.containsKey(key)) {
    142                    natTable.put(key, Integer.valueOf(i));
    143                }
    144            } else if (c instanceof ConstantUtf8) {
    145                final ConstantUtf8 u = (ConstantUtf8) c;
    146                final String key = u.getBytes();
    147                if (!utf8Table.containsKey(key)) {
    148                    utf8Table.put(key, Integer.valueOf(i));
    149                }
    150            } else if (c instanceof ConstantCP) {
    151                final ConstantCP m = (ConstantCP) c;
    152                String className;
    153                ConstantUtf8 u8;
    154
    155                if (c instanceof ConstantInvokeDynamic) {
    156                    className = Integer.toString(((ConstantInvokeDynamic) m).getBootstrapMethodAttrIndex());
    157                } else if (c instanceof ConstantDynamic) {
    158                    className = Integer.toString(((ConstantDynamic) m).getBootstrapMethodAttrIndex());
    159                } else {
    160                    final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
    161                    u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
    162                    className = Utility.pathToPackage(u8.getBytes());
    163                }
    164
    165                final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
    166                u8 = (ConstantUtf8) constants[n.getNameIndex()];
    167                final String methodName = u8.getBytes();
    168                u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
    169                final String signature = u8.getBytes();
    170
    171                // Since name cannot begin with digit, we can use METHODREF_DELIM without fear of duplicates
    172                String delim = METHODREF_DELIM;
    173                if (c instanceof ConstantInterfaceMethodref) {
    174                    delim = IMETHODREF_DELIM;
    175                } else if (c instanceof ConstantFieldref) {
    176                    delim = FIELDREF_DELIM;
    177                }
    178
    179                sb.append(className);
    180                sb.append(delim);
    181                sb.append(methodName);
    182                sb.append(delim);
    183                sb.append(signature);
    184                final String key = sb.toString();
    185                sb.delete(0, sb.length());
    186
    187                if (!cpTable.containsKey(key)) {
    188                    cpTable.put(key, Integer.valueOf(i));
    189                }
    190            }
    191//            else if (c == null) { // entries may be null
    192//                // nothing to do
    193//            } else if (c instanceof ConstantInteger) {
    194//                // nothing to do
    195//            } else if (c instanceof ConstantLong) {
    196//                // nothing to do
    197//            } else if (c instanceof ConstantFloat) {
    198//                // nothing to do
    199//            } else if (c instanceof ConstantDouble) {
    200//                // nothing to do
    201//            } else if (c instanceof org.apache.bcel.classfile.ConstantMethodType) {
    202//                // TODO should this be handled somehow?
    203//            } else if (c instanceof org.apache.bcel.classfile.ConstantMethodHandle) {
    204//                // TODO should this be handled somehow?
    205//            } else if (c instanceof org.apache.bcel.classfile.ConstantModule) {
    206//                // TODO should this be handled somehow?
    207//            } else if (c instanceof org.apache.bcel.classfile.ConstantPackage) {
    208//                // TODO should this be handled somehow?
    209//            } else {
    210//                // Not helpful, should throw an exception.
    211//                assert false : "Unexpected constant type: " + c.getClass().getName();
    212//            }
    213        }
    214    }
    215
    216    /**
    217     * Constructs a new instance with the given constant pool.
    218     *
    219     * @param cp the constant pool.
    220     */
    221    public ConstantPoolGen(final ConstantPool cp) {
    222        this(cp.getConstantPool());
    223    }
    224
    225    /**
    226     * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY instruction, e.g. to the
    227     * 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}