    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    /**
    406     * Adds a new InterfaceMethodref constant to the ConstantPool.
    407     *
    408     * @param method the method to add.
    409     * @return index of entry.
    410     */
    411    public int addInterfaceMethodref(final MethodGen method) {
    412        return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
    413    }
    414
    415    /**
    416     * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there.
    417     *
    418     * @param className class name string to add.
    419     * @param methodName method name string to add.
    420     * @param signature signature string to add.
    421     * @return index of entry.
    422     */
    423    public int addInterfaceMethodref(final String className, final String methodName, final String signature) {
    424        final int cpRet;
    425        if ((cpRet = lookupInterfaceMethodref(className, methodName, signature)) != -1) {
    426            return cpRet; // Already in CP
    427        }
    428        adjustSize();
    429        final int classIndex = addClass(className);
    430        final int nameAndTypeIndex = addNameAndType(methodName, signature);
    431        final int ret = index;
    432        constants[index++] = new ConstantInterfaceMethodref(classIndex, nameAndTypeIndex);
    433        return computeIfAbsent(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature, ret);
    434    }
    435
    436    /**
    437     * Add a new long constant to the ConstantPool, if it is not already in there.
    438     *
    439     * @param n Long number to add.
    440     * @return index of entry.
    441     */
    442    public int addLong(final long n) {
    443        int ret;
    444        if ((ret = lookupLong(n)) != -1) {
    445            return ret; // Already in CP
    446        }
    447        adjustSize();
    448        ret = index;
    449        constants[index] = new ConstantLong(n);
    450        index += 2; // Wastes one entry according to spec
    451        return ret;
    452    }
    453
    454    /**
    455     * Adds a new Methodref constant to the ConstantPool.
    456     *
    457     * @param method the method to add.
    458     * @return index of entry.
    459     */
    460    public int addMethodref(final MethodGen method) {
    461        return addMethodref(method.getClassName(), method.getName(), method.getSignature());
    462    }
    463
    464    /**
    465     * Add a new Methodref constant to the ConstantPool, if it is not already in there.
    466     *
    467     * @param className class name string to add.
    468     * @param methodName method name string to add.
    469     * @param signature method signature string to add.
    470     * @return index of entry.
    471     */
    472    public int addMethodref(final String className, final String methodName, final String signature) {
    473        final int cpRet;
    474        if ((cpRet = lookupMethodref(className, methodName, signature)) != -1) {
    475            return cpRet; // Already in CP
    476        }
    477        adjustSize();
    478        final int nameAndTypeIndex = addNameAndType(methodName, signature);
    479        final int classIndex = addClass(className);
    480        final int ret = index;
    481        constants[index++] = new ConstantMethodref(classIndex, nameAndTypeIndex);
    482        return computeIfAbsent(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature, ret);
    483    }
    484
    485    /**
    486     * Add a new NameAndType constant to the ConstantPool if it is not already in there.
    487     *
    488     * @param name Name string to add.
    489     * @param signature signature string to add.
    490     * @return index of entry.
    491     */
    492    public int addNameAndType(final String name, final String signature) {
    493        int ret;
    494        if ((ret = lookupNameAndType(name, signature)) != -1) {
    495            return ret; // Already in CP
    496        }
    497        adjustSize();
    498        final int nameIndex = addUtf8(name);
    499        final int signatureIndex = addUtf8(signature);
    500        ret = index;
    501        constants[index++] = new ConstantNameAndType(nameIndex, signatureIndex);
    502        return computeIfAbsent(natTable, name + NAT_DELIM + signature, ret);
    503    }
    504
    505    /**
    506     * Add a new String constant to the ConstantPool, if it is not already in there.
    507     *
    508     * @param str String to add.
    509     * @return index of entry.
    510     */
    511    public int addString(final String str) {
    512        int ret;
    513        if ((ret = lookupString(str)) != -1) {
    514            return ret; // Already in CP
    515        }
    516        final int utf8 = addUtf8(str);
    517        adjustSize();
    518        final ConstantString s = new ConstantString(utf8);
    519        ret = index;
    520        constants[index++] = s;
    521        return computeIfAbsent(stringTable, str, ret);
    522    }
    523
    524    /**
    525     * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
    526     *
    527     * @param n Utf8 string to add.
    528     * @return index of entry.
    529     */
    530    public int addUtf8(final String n) {
    531        int ret;
    532        if ((ret = lookupUtf8(n)) != -1) {
    533            return ret; // Already in CP
    534        }
    535        adjustSize();
    536        ret = index;
    537        constants[index++] = new ConstantUtf8(n);
    538        return computeIfAbsent(utf8Table, n, ret);
    539    }
    540
    541    /**
    542     * Resize internal array of constants.
    543     */
    544    protected void adjustSize() {
    545        // 3 extra spaces are needed as some entries may take 3 slots
    546        if (index + 3 >= Const.MAX_CP_ENTRIES + 1) {
    547            throw new IllegalStateException("The number of constants " + (index + 3)
    548                    + " is over the size of the constant pool: "
    549                    + Const.MAX_CP_ENTRIES);
    550        }
    551
    552        if (index + 3 >= size) {
    553            final Constant[] tmp = constants;
    554            size *= 2;
    555            // the constant array shall not exceed the size of the constant pool
    556            size = Math.min(size, Const.MAX_CP_ENTRIES + 1);
    557            constants = new Constant[size];
    558            System.arraycopy(tmp, 0, constants, 0, index);
    559        }
    560    }
    561
    562    private int computeIfAbsent(final Map<String, Integer> map, final String key, final int value) {
    563        return map.computeIfAbsent(key, k -> Integer.valueOf(value));
    564    }
    565
    566    /**
    567     * Gets a constant pool entry at the specified index.
    568     *
    569     * @param i index in constant pool.
    570     * @return constant pool entry at index i.
    571     */
    572    public Constant getConstant(final int i) {
    573        return constants[i];
    574    }
    575
    576    /**
    577     * Gets the intermediate constant pool.
    578     *
    579     * @return intermediate constant pool.
    580     */
    581    public ConstantPool getConstantPool() {
    582        return new ConstantPool(constants);
    583    }
    584
    585    /**
    586     * Gets the constant pool with proper length.
    587     *
    588     * @return constant pool with proper length.
    589     */
    590    public ConstantPool getFinalConstantPool() {
    591        return new ConstantPool(Arrays.copyOf(constants, index));
    592    }
    593
    594    private int getIndex(final Map<String, Integer> map, final String key) {
    595        return toIndex(map.get(key));
    596    }
    597
    598    /**
    599     * Gets the current size of constant pool.
    600     *
    601     * @return current size of constant pool.
    602     */
    603    public int getSize() {
    604        return index;
    605    }
    606
    607    /**
    608     * Look for ConstantClass in ConstantPool named 'str'.
    609     *
    610     * @param str String to search for.
    611     * @return index on success, -1 otherwise.
    612     */
    613    public int lookupClass(final String str) {
    614        return getIndex(classTable, Utility.packageToPath(str));
    615    }
    616
    617    /**
    618     * Look for ConstantDouble in ConstantPool.
    619     *
    620     * @param n Double number to look for.
    621     * @return index on success, -1 otherwise.
    622     */
    623    public int lookupDouble(final double n) {
    624        final long bits = Double.doubleToLongBits(n);
    625        for (int i = 1; i < index; i++) {
    626            if (constants[i] instanceof ConstantDouble) {
    627                final ConstantDouble c = (ConstantDouble) constants[i];
    628                if (Double.doubleToLongBits(c.getBytes()) == bits) {
    629                    return i;
    630                }
    631            }
    632        }
    633        return -1;
    634    }
    635
    636    /**
    637     * Look for ConstantFieldref in ConstantPool.
    638     *
    639     * @param className Where to find method.
    640     * @param fieldName Guess what.
    641     * @param signature return and argument types.
    642     * @return index on success, -1 otherwise.
    643     */
    644    public int lookupFieldref(final String className, final String fieldName, final String signature) {
    645        return getIndex(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature);
    646    }
    647
    648    /**
    649     * Look for ConstantFloat in ConstantPool.
    650     *
    651     * @param n Float number to look for.
    652     * @return index on success, -1 otherwise.
    653     */
    654    public int lookupFloat(final float n) {
    655        final int bits = Float.floatToIntBits(n);
    656        for (int i = 1; i < index; i++) {
    657            if (constants[i] instanceof ConstantFloat) {
    658                final ConstantFloat c = (ConstantFloat) constants[i];
    659                if (Float.floatToIntBits(c.getBytes()) == bits) {
    660                    return i;
    661                }
    662            }
    663        }
    664        return -1;
    665    }
    666
    667    /**
    668     * Look for ConstantInteger in ConstantPool.
    669     *
    670     * @param n integer number to look for.
    671     * @return index on success, -1 otherwise.
    672     */
    673    public int lookupInteger(final int n) {
    674        for (int i = 1; i < index; i++) {
    675            if (constants[i] instanceof ConstantInteger) {
    676                final ConstantInteger c = (ConstantInteger) constants[i];
    677                if (c.getBytes() == n) {
    678                    return i;
    679                }
    680            }
    681        }
    682        return -1;
    683    }
    684
    685    /**
    686     * Looks up an InterfaceMethodref in the ConstantPool.
    687     *
    688     * @param method the method to look for.
    689     * @return index on success, -1 otherwise.
    690     */
    691    public int lookupInterfaceMethodref(final MethodGen method) {
    692        return lookupInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
    693    }
    694
    695    /**
    696     * Look for ConstantInterfaceMethodref in ConstantPool.
    697     *
    698     * @param className Where to find method.
    699     * @param methodName Guess what.
    700     * @param signature return and argument types.
    701     * @return index on success, -1 otherwise.
    702     */
    703    public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) {
    704        return getIndex(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature);
    705    }
    706
    707    /**
    708     * Look for ConstantLong in ConstantPool.
    709     *
    710     * @param n Long number to look for.
    711     * @return index on success, -1 otherwise.
    712     */
    713    public int lookupLong(final long n) {
    714        for (int i = 1; i < index; i++) {
    715            if (constants[i] instanceof ConstantLong) {
    716                final ConstantLong c = (ConstantLong) constants[i];
    717                if (c.getBytes() == n) {
    718                    return i;
    719                }
    720            }
    721        }
    722        return -1;
    723    }
    724
    725    /**
    726     * Looks up a Methodref in the ConstantPool.
    727     *
    728     * @param method the method to look for.
    729     * @return index on success, -1 otherwise.
    730     */
    731    public int lookupMethodref(final MethodGen method) {
    732        return lookupMethodref(method.getClassName(), method.getName(), method.getSignature());
    733    }
    734
    735    /**
    736     * Look for ConstantMethodref in ConstantPool.
    737     *
    738     * @param className Where to find method.
    739     * @param methodName Guess what.
    740     * @param signature return and argument types.
    741     * @return index on success, -1 otherwise.
    742     */
    743    public int lookupMethodref(final String className, final String methodName, final String signature) {
    744        return getIndex(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature);
    745    }
    746
    747    /**
    748     * Look for ConstantNameAndType in ConstantPool.
    749     *
    750     * @param name of variable/method.
    751     * @param signature of variable/method.
    752     * @return index on success, -1 otherwise.
    753     */
    754    public int lookupNameAndType(final String name, final String signature) {
    755        return getIndex(natTable, name + NAT_DELIM + signature);
    756    }
    757
    758    /**
    759     * Look for ConstantString in ConstantPool containing String 'str'.
    760     *
    761     * @param str String to search for.
    762     * @return index on success, -1 otherwise.
    763     */
    764    public int lookupString(final String str) {
    765        return getIndex(stringTable, str);
    766    }
    767
    768    /**
    769     * Look for ConstantUtf8 in ConstantPool.
    770     *
    771     * @param n Utf8 string to look for.
    772     * @return index on success, -1 otherwise.
    773     */
    774    public int lookupUtf8(final String n) {
    775        return getIndex(utf8Table, n);
    776    }
    777
    778    /**
    779     * Use with care!
    780     *
    781     * @param i index in constant pool.
    782     * @param c new constant pool entry at index i.
    783     */
    784    public void setConstant(final int i, final Constant c) {
    785        constants[i] = c;
    786    }
    787
    788    private int toIndex(final Integer index) {
    789        return index != null ? index.intValue() : -1;
    790    }
    791
    792    /**
    793     * @return String representation.
    794     */
    795    @Override
    796    public String toString() {
    797        final StringBuilder buf = new StringBuilder();
    798        for (int i = 1; i < index; i++) {
    799            buf.append(i).append(")").append(constants[i]).append("\n");
    800        }
    801        return buf.toString();
    802    }
    803}