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}