    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     * Create empty constant pool.
    093     */
    094    public ConstantPoolGen() {
    095        size = DEFAULT_BUFFER_SIZE;
    096        constants = new Constant[size];
    097    }
    098
    099    /**
    100     * Initialize with 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 = new Constant[size];
    109
    110        System.arraycopy(cs, 0, constants, 0, cs.length);
    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 u8 = (ConstantUtf8) constants[n.getNameIndex()];
    134                final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
    135
    136                sb.append(u8.getBytes());
    137                sb.append(NAT_DELIM);
    138                sb.append(u8_2.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                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     * Initialize with 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 (e.g. String[][]) as needed by MULTIANEWARRAY instruction, e.g. to the
    228     * ConstantPool.
    229     *
    230     * @param type type of array class
    231     * @return index of entry
    232     */
    233    public int addArrayClass(final ArrayType type) {
    234        return addClass_(type.getSignature());
    235    }
    236
    237    /**
    238     * Add a new Class reference to the ConstantPool for a given type.
    239     *
    240     * @param type Class to add
    241     * @return index of entry
    242     */
    243    public int addClass(final ObjectType type) {
    244        return addClass(type.getClassName());
    245    }
    246
    247    /**
    248     * Add a new Class reference to the ConstantPool, if it is not already in there.
    249     *
    250     * @param str Class to add
    251     * @return index of entry
    252     */
    253    public int addClass(final String str) {
    254        return addClass_(str.replace('.', '/'));
    255    }
    256
    257    private int addClass_(final String clazz) {
    258        final int cpRet;
    259        if ((cpRet = lookupClass(clazz)) != -1) {
    260            return cpRet; // Already in CP
    261        }
    262        adjustSize();
    263        final ConstantClass c = new ConstantClass(addUtf8(clazz));
    264        final int ret = index;
    265        constants[index++] = c;
    266        return computeIfAbsent(classTable, clazz, ret);
    267    }
    268
    269    /**
    270     * Import constant from another ConstantPool and return new index.
    271     */
    272    public int addConstant(final Constant c, final ConstantPoolGen cp) {
    273        final Constant[] constants = cp.getConstantPool().getConstantPool();
    274        switch (c.getTag()) {
    275        case Const.CONSTANT_String: {
    276            final ConstantString s = (ConstantString) c;
    277            final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
    278            return addString(u8.getBytes());
    279        }
    280        case Const.CONSTANT_Class: {
    281            final ConstantClass s = (ConstantClass) c;
    282            final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
    283            return addClass(u8.getBytes());
    284        }
    285        case Const.CONSTANT_NameAndType: {
    286            final ConstantNameAndType n = (ConstantNameAndType) c;
    287            final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
    288            final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
    289            return addNameAndType(u8.getBytes(), u8_2.getBytes());
    290        }
    291        case Const.CONSTANT_Utf8:
    292            return addUtf8(((ConstantUtf8) c).getBytes());
    293        case Const.CONSTANT_Double:
    294            return addDouble(((ConstantDouble) c).getBytes());
    295        case Const.CONSTANT_Float:
    296            return addFloat(((ConstantFloat) c).getBytes());
    297        case Const.CONSTANT_Long:
    298            return addLong(((ConstantLong) c).getBytes());
    299        case Const.CONSTANT_Integer:
    300            return addInteger(((ConstantInteger) c).getBytes());
    301        case Const.CONSTANT_InterfaceMethodref:
    302        case Const.CONSTANT_Methodref:
    303        case Const.CONSTANT_Fieldref: {
    304            final ConstantCP m = (ConstantCP) c;
    305            final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
    306            final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
    307            ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
    308            final String className = Utility.pathToPackage(u8.getBytes());
    309            u8 = (ConstantUtf8) constants[n.getNameIndex()];
    310            final String name = u8.getBytes();
    311            u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
    312            final String signature = u8.getBytes();
    313            switch (c.getTag()) {
    314            case Const.CONSTANT_InterfaceMethodref:
    315                return addInterfaceMethodref(className, name, signature);
    316            case Const.CONSTANT_Methodref:
    317                return addMethodref(className, name, signature);
    318            case Const.CONSTANT_Fieldref:
    319                return addFieldref(className, name, signature);
    320            default: // Never reached
    321                throw new IllegalArgumentException("Unknown constant type " + c);
    322            }
    323        }
    324        default: // Never reached
    325            throw new IllegalArgumentException("Unknown constant type " + c);
    326        }
    327    }
    328
    329    /**
    330     * Add a new double constant to the ConstantPool, if it is not already in there.
    331     *
    332     * @param n Double number to add
    333     * @return index of entry
    334     */
    335    public int addDouble(final double n) {
    336        int ret;
    337        if ((ret = lookupDouble(n)) != -1) {
    338            return ret; // Already in CP
    339        }
    340        adjustSize();
    341        ret = index;
    342        constants[index] = new ConstantDouble(n);
    343        index += 2; // Wastes one entry according to spec
    344        return ret;
    345    }
    346
    347    /**
    348     * Add a new Fieldref constant to the ConstantPool, if it is not already in there.
    349     *
    350     * @param className class name string to add
    351     * @param fieldName field name string to add
    352     * @param signature signature string to add
    353     * @return index of entry
    354     */
    355    public int addFieldref(final String className, final String fieldName, final String signature) {
    356        final int cpRet;
    357        if ((cpRet = lookupFieldref(className, fieldName, signature)) != -1) {
    358            return cpRet; // Already in CP
    359        }
    360        adjustSize();
    361        int classIndex = addClass(className);
    362        int nameAndTypeIndex = addNameAndType(fieldName, signature);
    363        final int ret = index;
    364        constants[index++] = new ConstantFieldref(classIndex, nameAndTypeIndex);
    365        return computeIfAbsent(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature, ret);
    366    }
    367
    368    /**
    369     * Add a new Float constant to the ConstantPool, if it is not already in there.
    370     *
    371     * @param n Float number to add
    372     * @return index of entry
    373     */
    374    public int addFloat(final float n) {
    375        int ret;
    376        if ((ret = lookupFloat(n)) != -1) {
    377            return ret; // Already in CP
    378        }
    379        adjustSize();
    380        ret = index;
    381        constants[index++] = new ConstantFloat(n);
    382        return ret;
    383    }
    384
    385    /**
    386     * Add a new Integer constant to the ConstantPool, if it is not already in there.
    387     *
    388     * @param n integer number to add
    389     * @return index of entry
    390     */
    391    public int addInteger(final int n) {
    392        int ret;
    393        if ((ret = lookupInteger(n)) != -1) {
    394            return ret; // Already in CP
    395        }
    396        adjustSize();
    397        ret = index;
    398        constants[index++] = new ConstantInteger(n);
    399        return ret;
    400    }
    401
    402    public int addInterfaceMethodref(final MethodGen method) {
    403        return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
    404    }
    405
    406    /**
    407     * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there.
    408     *
    409     * @param className class name string to add
    410     * @param methodName method name string to add
    411     * @param signature signature string to add
    412     * @return index of entry
    413     */
    414    public int addInterfaceMethodref(final String className, final String methodName, final String signature) {
    415        final int cpRet;
    416        if ((cpRet = lookupInterfaceMethodref(className, methodName, signature)) != -1) {
    417            return cpRet; // Already in CP
    418        }
    419        adjustSize();
    420        int classIndex = addClass(className);
    421        int nameAndTypeIndex = addNameAndType(methodName, signature);
    422        final int ret = index;
    423        constants[index++] = new ConstantInterfaceMethodref(classIndex, nameAndTypeIndex);
    424        return computeIfAbsent(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature, ret);
    425    }
    426
    427    /**
    428     * Add a new long constant to the ConstantPool, if it is not already in there.
    429     *
    430     * @param n Long number to add
    431     * @return index of entry
    432     */
    433    public int addLong(final long n) {
    434        int ret;
    435        if ((ret = lookupLong(n)) != -1) {
    436            return ret; // Already in CP
    437        }
    438        adjustSize();
    439        ret = index;
    440        constants[index] = new ConstantLong(n);
    441        index += 2; // Wastes one entry according to spec
    442        return ret;
    443    }
    444    public int addMethodref(final MethodGen method) {
    445        return addMethodref(method.getClassName(), method.getName(), method.getSignature());
    446    }
    447
    448    /**
    449     * Add a new Methodref constant to the ConstantPool, if it is not already in there.
    450     *
    451     * @param className class name string to add
    452     * @param methodName method name string to add
    453     * @param signature method signature string to add
    454     * @return index of entry
    455     */
    456    public int addMethodref(final String className, final String methodName, final String signature) {
    457        final int cpRet;
    458        if ((cpRet = lookupMethodref(className, methodName, signature)) != -1) {
    459            return cpRet; // Already in CP
    460        }
    461        adjustSize();
    462        int nameAndTypeIndex = addNameAndType(methodName, signature);
    463        int classIndex = addClass(className);
    464        final int ret = index;
    465        constants[index++] = new ConstantMethodref(classIndex, nameAndTypeIndex);
    466        return computeIfAbsent(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature, ret);
    467    }
    468
    469    /**
    470     * Add a new NameAndType constant to the ConstantPool if it is not already in there.
    471     *
    472     * @param name Name string to add
    473     * @param signature signature string to add
    474     * @return index of entry
    475     */
    476    public int addNameAndType(final String name, final String signature) {
    477        int ret;
    478        if ((ret = lookupNameAndType(name, signature)) != -1) {
    479            return ret; // Already in CP
    480        }
    481        adjustSize();
    482        int nameIndex = addUtf8(name);
    483        int signatureIndex = addUtf8(signature);
    484        ret = index;
    485        constants[index++] = new ConstantNameAndType(nameIndex, signatureIndex);
    486        return computeIfAbsent(natTable, name + NAT_DELIM + signature, ret);
    487    }
    488
    489    /**
    490     * Add a new String constant to the ConstantPool, if it is not already in there.
    491     *
    492     * @param str String to add
    493     * @return index of entry
    494     */
    495    public int addString(final String str) {
    496        int ret;
    497        if ((ret = lookupString(str)) != -1) {
    498            return ret; // Already in CP
    499        }
    500        final int utf8 = addUtf8(str);
    501        adjustSize();
    502        final ConstantString s = new ConstantString(utf8);
    503        ret = index;
    504        constants[index++] = s;
    505        return computeIfAbsent(stringTable, str, ret);
    506    }
    507
    508    /**
    509     * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
    510     *
    511     * @param n Utf8 string to add
    512     * @return index of entry
    513     */
    514    public int addUtf8(final String n) {
    515        int ret;
    516        if ((ret = lookupUtf8(n)) != -1) {
    517            return ret; // Already in CP
    518        }
    519        adjustSize();
    520        ret = index;
    521        constants[index++] = new ConstantUtf8(n);
    522        return computeIfAbsent(utf8Table, n, ret);
    523    }
    524
    525    /**
    526     * Resize internal array of constants.
    527     */
    528    protected void adjustSize() {
    529        // 3 extra spaces are needed as some entries may take 3 slots
    530        if (index + 3 >= Const.MAX_CP_ENTRIES + 1) {
    531            throw new IllegalStateException("The number of constants " + (index + 3)
    532                    + " is over the size of the constant pool: "
    533                    + Const.MAX_CP_ENTRIES);
    534        }
    535
    536        if (index + 3 >= size) {
    537            final Constant[] cs = constants;
    538            size *= 2;
    539            // the constant array shall not exceed the size of the constant pool
    540            size = Math.min(size, Const.MAX_CP_ENTRIES + 1);
    541            constants = new Constant[size];
    542            System.arraycopy(cs, 0, constants, 0, index);
    543        }
    544    }
    545
    546    private int computeIfAbsent(final Map<String, Integer> map, final String key, final int value) {
    547        return map.computeIfAbsent(key, k -> Integer.valueOf(value));
    548    }
    549
    550    /**
    551     * @param i index in constant pool
    552     * @return constant pool entry at index i
    553     */
    554    public Constant getConstant(final int i) {
    555        return constants[i];
    556    }
    557
    558    /**
    559     * @return intermediate constant pool
    560     */
    561    public ConstantPool getConstantPool() {
    562        return new ConstantPool(constants);
    563    }
    564
    565    /**
    566     * @return constant pool with proper length
    567     */
    568    public ConstantPool getFinalConstantPool() {
    569        return new ConstantPool(Arrays.copyOf(constants, index));
    570    }
    571
    572    private int getIndex(final Map<String, Integer> map, final String key) {
    573        return toIndex(map.get(key));
    574    }
    575
    576    /**
    577     * @return current size of constant pool
    578     */
    579    public int getSize() {
    580        return index;
    581    }
    582
    583    /**
    584     * Look for ConstantClass in ConstantPool named `str'.
    585     *
    586     * @param str String to search for
    587     * @return index on success, -1 otherwise
    588     */
    589    public int lookupClass(final String str) {
    590        return getIndex(classTable, str.replace('.', '/'));
    591    }
    592
    593    /**
    594     * Look for ConstantDouble in ConstantPool.
    595     *
    596     * @param n Double number to look for
    597     * @return index on success, -1 otherwise
    598     */
    599    public int lookupDouble(final double n) {
    600        final long bits = Double.doubleToLongBits(n);
    601        for (int i = 1; i < index; i++) {
    602            if (constants[i] instanceof ConstantDouble) {
    603                final ConstantDouble c = (ConstantDouble) constants[i];
    604                if (Double.doubleToLongBits(c.getBytes()) == bits) {
    605                    return i;
    606                }
    607            }
    608        }
    609        return -1;
    610    }
    611
    612    /**
    613     * Look for ConstantFieldref in ConstantPool.
    614     *
    615     * @param className Where to find method
    616     * @param fieldName Guess what
    617     * @param signature return and argument types
    618     * @return index on success, -1 otherwise
    619     */
    620    public int lookupFieldref(final String className, final String fieldName, final String signature) {
    621        return getIndex(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature);
    622    }
    623
    624    /**
    625     * Look for ConstantFloat in ConstantPool.
    626     *
    627     * @param n Float number to look for
    628     * @return index on success, -1 otherwise
    629     */
    630    public int lookupFloat(final float n) {
    631        final int bits = Float.floatToIntBits(n);
    632        for (int i = 1; i < index; i++) {
    633            if (constants[i] instanceof ConstantFloat) {
    634                final ConstantFloat c = (ConstantFloat) constants[i];
    635                if (Float.floatToIntBits(c.getBytes()) == bits) {
    636                    return i;
    637                }
    638            }
    639        }
    640        return -1;
    641    }
    642
    643    /**
    644     * Look for ConstantInteger in ConstantPool.
    645     *
    646     * @param n integer number to look for
    647     * @return index on success, -1 otherwise
    648     */
    649    public int lookupInteger(final int n) {
    650        for (int i = 1; i < index; i++) {
    651            if (constants[i] instanceof ConstantInteger) {
    652                final ConstantInteger c = (ConstantInteger) constants[i];
    653                if (c.getBytes() == n) {
    654                    return i;
    655                }
    656            }
    657        }
    658        return -1;
    659    }
    660
    661    public int lookupInterfaceMethodref(final MethodGen method) {
    662        return lookupInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
    663    }
    664
    665    /**
    666     * Look for ConstantInterfaceMethodref in ConstantPool.
    667     *
    668     * @param className Where to find method
    669     * @param methodName Guess what
    670     * @param signature return and argument types
    671     * @return index on success, -1 otherwise
    672     */
    673    public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) {
    674        return getIndex(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature);
    675    }
    676
    677    /**
    678     * Look for ConstantLong in ConstantPool.
    679     *
    680     * @param n Long number to look for
    681     * @return index on success, -1 otherwise
    682     */
    683    public int lookupLong(final long n) {
    684        for (int i = 1; i < index; i++) {
    685            if (constants[i] instanceof ConstantLong) {
    686                final ConstantLong c = (ConstantLong) constants[i];
    687                if (c.getBytes() == n) {
    688                    return i;
    689                }
    690            }
    691        }
    692        return -1;
    693    }
    694
    695    public int lookupMethodref(final MethodGen method) {
    696        return lookupMethodref(method.getClassName(), method.getName(), method.getSignature());
    697    }
    698
    699    /**
    700     * Look for ConstantMethodref in ConstantPool.
    701     *
    702     * @param className Where to find method
    703     * @param methodName Guess what
    704     * @param signature return and argument types
    705     * @return index on success, -1 otherwise
    706     */
    707    public int lookupMethodref(final String className, final String methodName, final String signature) {
    708        return getIndex(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature);
    709    }
    710
    711    /**
    712     * Look for ConstantNameAndType in ConstantPool.
    713     *
    714     * @param name of variable/method
    715     * @param signature of variable/method
    716     * @return index on success, -1 otherwise
    717     */
    718    public int lookupNameAndType(final String name, final String signature) {
    719        return getIndex(natTable, name + NAT_DELIM + signature);
    720    }
    721
    722    /**
    723     * Look for ConstantString in ConstantPool containing String `str'.
    724     *
    725     * @param str String to search for
    726     * @return index on success, -1 otherwise
    727     */
    728    public int lookupString(final String str) {
    729        return getIndex(stringTable, str);
    730    }
    731
    732    /**
    733     * Look for ConstantUtf8 in ConstantPool.
    734     *
    735     * @param n Utf8 string to look for
    736     * @return index on success, -1 otherwise
    737     */
    738    public int lookupUtf8(final String n) {
    739        return getIndex(utf8Table, n);
    740    }
    741
    742    /**
    743     * Use with care!
    744     *
    745     * @param i index in constant pool
    746     * @param c new constant pool entry at index i
    747     */
    748    public void setConstant(final int i, final Constant c) {
    749        constants[i] = c;
    750    }
    751
    752    private int toIndex(final Integer index) {
    753        return index != null ? index.intValue() : -1;
    754    }
    755
    756    /**
    757     * @return String representation.
    758     */
    759    @Override
    760    public String toString() {
    761        final StringBuilder buf = new StringBuilder();
    762        for (int i = 1; i < index; i++) {
    763            buf.append(i).append(")").append(constants[i]).append("\n");
    764        }
    765        return buf.toString();
    766    }
    767}