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