001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 */
017package org.apache.bcel.generic;
018
019import java.util.Arrays;
020import java.util.HashMap;
021import java.util.Map;
022
023import org.apache.bcel.Const;
024import org.apache.bcel.classfile.Constant;
025import org.apache.bcel.classfile.ConstantCP;
026import org.apache.bcel.classfile.ConstantClass;
027import org.apache.bcel.classfile.ConstantDouble;
028import org.apache.bcel.classfile.ConstantDynamic;
029import org.apache.bcel.classfile.ConstantFieldref;
030import org.apache.bcel.classfile.ConstantFloat;
031import org.apache.bcel.classfile.ConstantInteger;
032import org.apache.bcel.classfile.ConstantInterfaceMethodref;
033import org.apache.bcel.classfile.ConstantInvokeDynamic;
034import org.apache.bcel.classfile.ConstantLong;
035import org.apache.bcel.classfile.ConstantMethodref;
036import org.apache.bcel.classfile.ConstantNameAndType;
037import org.apache.bcel.classfile.ConstantPool;
038import org.apache.bcel.classfile.ConstantString;
039import org.apache.bcel.classfile.ConstantUtf8;
040import org.apache.bcel.classfile.Utility;
041
042/**
043 * This class is used to build up a constant pool. The user adds constants via 'addXXX' methods, 'addString',
044 * 'addClass', etc.. These methods return an index into the constant pool. Finally, 'getFinalConstantPool()' returns the
045 * constant pool built up. Intermediate versions of the constant pool can be obtained with 'getConstantPool()'. A
046 * constant pool has capacity for Constants.MAX_SHORT entries. Note that the first (0) is used by the JVM and that
047 * Double and Long constants need two slots.
048 *
049 * @see Constant
050 */
051public class ConstantPoolGen {
052
053    private static final int DEFAULT_BUFFER_SIZE = 256;
054
055    private static final String METHODREF_DELIM = ":";
056
057    private static final String IMETHODREF_DELIM = "#";
058
059    private static final String FIELDREF_DELIM = "&";
060
061    private static final String NAT_DELIM = "%"; // Name and Type
062
063    /**
064     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
065     */
066    @Deprecated
067    protected int size;
068
069    /**
070     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
071     */
072    @Deprecated
073    protected Constant[] constants;
074
075    /**
076     * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
077     */
078    @Deprecated
079    protected int index = 1; // First entry (0) used by JVM
080
081    private final Map<String, Integer> stringTable = new HashMap<>();
082
083    private final Map<String, Integer> classTable = new HashMap<>();
084
085    private final Map<String, Integer> utf8Table = new HashMap<>();
086
087    private final Map<String, Integer> natTable = new HashMap<>();
088
089    private final Map<String, Integer> cpTable = new HashMap<>();
090
091    /**
092     * Constructs a new empty constant pool.
093     */
094    public ConstantPoolGen() {
095        size = DEFAULT_BUFFER_SIZE;
096        constants = new Constant[size];
097    }
098
099    /**
100     * Constructs a new instance with the given array of constants.
101     *
102     * @param cs array of given constants, new ones will be appended
103     */
104    public ConstantPoolGen(final Constant[] cs) {
105        final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE);
106
107        size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), Const.MAX_CP_ENTRIES + 1);
108        constants = Arrays.copyOf(cs, size);
109
110        if (cs.length > 0) {
111            index = cs.length;
112        }
113
114        for (int i = 1; i < index; i++) {
115            final Constant c = constants[i];
116            if (c instanceof ConstantString) {
117                final ConstantString s = (ConstantString) c;
118                final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
119                final String key = u8.getBytes();
120                if (!stringTable.containsKey(key)) {
121                    stringTable.put(key, Integer.valueOf(i));
122                }
123            } else if (c instanceof ConstantClass) {
124                final ConstantClass s = (ConstantClass) c;
125                final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
126                final String key = u8.getBytes();
127                if (!classTable.containsKey(key)) {
128                    classTable.put(key, Integer.valueOf(i));
129                }
130            } else if (c instanceof ConstantNameAndType) {
131                final ConstantNameAndType n = (ConstantNameAndType) c;
132                final ConstantUtf8 u8NameIdx = (ConstantUtf8) constants[n.getNameIndex()];
133                final ConstantUtf8 u8SigIdx = (ConstantUtf8) constants[n.getSignatureIndex()];
134
135                sb.append(u8NameIdx.getBytes());
136                sb.append(NAT_DELIM);
137                sb.append(u8SigIdx.getBytes());
138                final String key = sb.toString();
139                sb.delete(0, sb.length());
140
141                if (!natTable.containsKey(key)) {
142                    natTable.put(key, Integer.valueOf(i));
143                }
144            } else if (c instanceof ConstantUtf8) {
145                final ConstantUtf8 u = (ConstantUtf8) c;
146                final String key = u.getBytes();
147                if (!utf8Table.containsKey(key)) {
148                    utf8Table.put(key, Integer.valueOf(i));
149                }
150            } else if (c instanceof ConstantCP) {
151                final ConstantCP m = (ConstantCP) c;
152                String className;
153                ConstantUtf8 u8;
154
155                if (c instanceof ConstantInvokeDynamic) {
156                    className = Integer.toString(((ConstantInvokeDynamic) m).getBootstrapMethodAttrIndex());
157                } else if (c instanceof ConstantDynamic) {
158                    className = Integer.toString(((ConstantDynamic) m).getBootstrapMethodAttrIndex());
159                } else {
160                    final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
161                    u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
162                    className = Utility.pathToPackage(u8.getBytes());
163                }
164
165                final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
166                u8 = (ConstantUtf8) constants[n.getNameIndex()];
167                final String methodName = u8.getBytes();
168                u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
169                final String signature = u8.getBytes();
170
171                // Since name cannot begin with digit, we can use METHODREF_DELIM without fear of duplicates
172                String delim = METHODREF_DELIM;
173                if (c instanceof ConstantInterfaceMethodref) {
174                    delim = IMETHODREF_DELIM;
175                } else if (c instanceof ConstantFieldref) {
176                    delim = FIELDREF_DELIM;
177                }
178
179                sb.append(className);
180                sb.append(delim);
181                sb.append(methodName);
182                sb.append(delim);
183                sb.append(signature);
184                final String key = sb.toString();
185                sb.delete(0, sb.length());
186
187                if (!cpTable.containsKey(key)) {
188                    cpTable.put(key, Integer.valueOf(i));
189                }
190            }
191//            else if (c == null) { // entries may be null
192//                // nothing to do
193//            } else if (c instanceof ConstantInteger) {
194//                // nothing to do
195//            } else if (c instanceof ConstantLong) {
196//                // nothing to do
197//            } else if (c instanceof ConstantFloat) {
198//                // nothing to do
199//            } else if (c instanceof ConstantDouble) {
200//                // nothing to do
201//            } else if (c instanceof org.apache.bcel.classfile.ConstantMethodType) {
202//                // TODO should this be handled somehow?
203//            } else if (c instanceof org.apache.bcel.classfile.ConstantMethodHandle) {
204//                // TODO should this be handled somehow?
205//            } else if (c instanceof org.apache.bcel.classfile.ConstantModule) {
206//                // TODO should this be handled somehow?
207//            } else if (c instanceof org.apache.bcel.classfile.ConstantPackage) {
208//                // TODO should this be handled somehow?
209//            } else {
210//                // Not helpful, should throw an exception.
211//                assert false : "Unexpected constant type: " + c.getClass().getName();
212//            }
213        }
214    }
215
216    /**
217     * Constructs a new instance with the given constant pool.
218     *
219     * @param cp the constant pool.
220     */
221    public ConstantPoolGen(final ConstantPool cp) {
222        this(cp.getConstantPool());
223    }
224
225    /**
226     * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY instruction, e.g. to the
227     * ConstantPool.
228     *
229     * @param type type of array class
230     * @return index of entry
231     */
232    public int addArrayClass(final ArrayType type) {
233        return addClass_(type.getSignature());
234    }
235
236    /**
237     * Add a new Class reference to the ConstantPool for a given type.
238     *
239     * @param type Class to add
240     * @return index of entry
241     */
242    public int addClass(final ObjectType type) {
243        return addClass(type.getClassName());
244    }
245
246    /**
247     * Add a new Class reference to the ConstantPool, if it is not already in there.
248     *
249     * @param str Class to add
250     * @return index of entry
251     */
252    public int addClass(final String str) {
253        return addClass_(Utility.packageToPath(str));
254    }
255
256    private int addClass_(final String clazz) {
257        final int cpRet;
258        if ((cpRet = lookupClass(clazz)) != -1) {
259            return cpRet; // Already in CP
260        }
261        adjustSize();
262        final ConstantClass c = new ConstantClass(addUtf8(clazz));
263        final int ret = index;
264        constants[index++] = c;
265        return computeIfAbsent(classTable, clazz, ret);
266    }
267
268    /**
269     * Adds a constant from another ConstantPool and returns the new index.
270     *
271     * @param constant The constant to add.
272     * @param cpGen Source pool.
273     * @return index of entry
274     */
275    public int addConstant(final Constant constant, final ConstantPoolGen cpGen) {
276        final Constant[] constants = cpGen.getConstantPool().getConstantPool();
277        switch (constant.getTag()) {
278        case Const.CONSTANT_String: {
279            final ConstantString s = (ConstantString) constant;
280            final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
281            return addString(u8.getBytes());
282        }
283        case Const.CONSTANT_Class: {
284            final ConstantClass s = (ConstantClass) constant;
285            final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
286            return addClass(u8.getBytes());
287        }
288        case Const.CONSTANT_NameAndType: {
289            final ConstantNameAndType n = (ConstantNameAndType) constant;
290            final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
291            final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
292            return addNameAndType(u8.getBytes(), u8_2.getBytes());
293        }
294        case Const.CONSTANT_Utf8:
295            return addUtf8(((ConstantUtf8) constant).getBytes());
296        case Const.CONSTANT_Double:
297            return addDouble(((ConstantDouble) constant).getBytes());
298        case Const.CONSTANT_Float:
299            return addFloat(((ConstantFloat) constant).getBytes());
300        case Const.CONSTANT_Long:
301            return addLong(((ConstantLong) constant).getBytes());
302        case Const.CONSTANT_Integer:
303            return addInteger(((ConstantInteger) constant).getBytes());
304        case Const.CONSTANT_InterfaceMethodref:
305        case Const.CONSTANT_Methodref:
306        case Const.CONSTANT_Fieldref: {
307            final ConstantCP m = (ConstantCP) constant;
308            final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
309            final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
310            ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
311            final String className = Utility.pathToPackage(u8.getBytes());
312            u8 = (ConstantUtf8) constants[n.getNameIndex()];
313            final String name = u8.getBytes();
314            u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
315            final String signature = u8.getBytes();
316            switch (constant.getTag()) {
317            case Const.CONSTANT_InterfaceMethodref:
318                return addInterfaceMethodref(className, name, signature);
319            case Const.CONSTANT_Methodref:
320                return addMethodref(className, name, signature);
321            case Const.CONSTANT_Fieldref:
322                return addFieldref(className, name, signature);
323            default: // Never reached
324                throw new IllegalArgumentException("Unknown constant type " + constant);
325            }
326        }
327        default: // Never reached
328            throw new IllegalArgumentException("Unknown constant type " + constant);
329        }
330    }
331
332    /**
333     * Add a new double constant to the ConstantPool, if it is not already in there.
334     *
335     * @param n Double number to add
336     * @return index of entry
337     */
338    public int addDouble(final double n) {
339        int ret;
340        if ((ret = lookupDouble(n)) != -1) {
341            return ret; // Already in CP
342        }
343        adjustSize();
344        ret = index;
345        constants[index] = new ConstantDouble(n);
346        index += 2; // Wastes one entry according to spec
347        return ret;
348    }
349
350    /**
351     * Add a new Fieldref constant to the ConstantPool, if it is not already in there.
352     *
353     * @param className class name string to add
354     * @param fieldName field name string to add
355     * @param signature signature string to add
356     * @return index of entry
357     */
358    public int addFieldref(final String className, final String fieldName, final String signature) {
359        final int cpRet;
360        if ((cpRet = lookupFieldref(className, fieldName, signature)) != -1) {
361            return cpRet; // Already in CP
362        }
363        adjustSize();
364        final int classIndex = addClass(className);
365        final int nameAndTypeIndex = addNameAndType(fieldName, signature);
366        final int ret = index;
367        constants[index++] = new ConstantFieldref(classIndex, nameAndTypeIndex);
368        return computeIfAbsent(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature, ret);
369    }
370
371    /**
372     * Add a new Float constant to the ConstantPool, if it is not already in there.
373     *
374     * @param n Float number to add
375     * @return index of entry
376     */
377    public int addFloat(final float n) {
378        int ret;
379        if ((ret = lookupFloat(n)) != -1) {
380            return ret; // Already in CP
381        }
382        adjustSize();
383        ret = index;
384        constants[index++] = new ConstantFloat(n);
385        return ret;
386    }
387
388    /**
389     * Add a new Integer constant to the ConstantPool, if it is not already in there.
390     *
391     * @param n integer number to add
392     * @return index of entry
393     */
394    public int addInteger(final int n) {
395        int ret;
396        if ((ret = lookupInteger(n)) != -1) {
397            return ret; // Already in CP
398        }
399        adjustSize();
400        ret = index;
401        constants[index++] = new ConstantInteger(n);
402        return ret;
403    }
404
405    public int addInterfaceMethodref(final MethodGen method) {
406        return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
407    }
408
409    /**
410     * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there.
411     *
412     * @param className class name string to add
413     * @param methodName method name string to add
414     * @param signature signature string to add
415     * @return index of entry
416     */
417    public int addInterfaceMethodref(final String className, final String methodName, final String signature) {
418        final int cpRet;
419        if ((cpRet = lookupInterfaceMethodref(className, methodName, signature)) != -1) {
420            return cpRet; // Already in CP
421        }
422        adjustSize();
423        final int classIndex = addClass(className);
424        final int nameAndTypeIndex = addNameAndType(methodName, signature);
425        final int ret = index;
426        constants[index++] = new ConstantInterfaceMethodref(classIndex, nameAndTypeIndex);
427        return computeIfAbsent(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature, ret);
428    }
429
430    /**
431     * Add a new long constant to the ConstantPool, if it is not already in there.
432     *
433     * @param n Long number to add
434     * @return index of entry
435     */
436    public int addLong(final long n) {
437        int ret;
438        if ((ret = lookupLong(n)) != -1) {
439            return ret; // Already in CP
440        }
441        adjustSize();
442        ret = index;
443        constants[index] = new ConstantLong(n);
444        index += 2; // Wastes one entry according to spec
445        return ret;
446    }
447    public int addMethodref(final MethodGen method) {
448        return addMethodref(method.getClassName(), method.getName(), method.getSignature());
449    }
450
451    /**
452     * Add a new Methodref constant to the ConstantPool, if it is not already in there.
453     *
454     * @param className class name string to add
455     * @param methodName method name string to add
456     * @param signature method signature string to add
457     * @return index of entry
458     */
459    public int addMethodref(final String className, final String methodName, final String signature) {
460        final int cpRet;
461        if ((cpRet = lookupMethodref(className, methodName, signature)) != -1) {
462            return cpRet; // Already in CP
463        }
464        adjustSize();
465        final int nameAndTypeIndex = addNameAndType(methodName, signature);
466        final int classIndex = addClass(className);
467        final int ret = index;
468        constants[index++] = new ConstantMethodref(classIndex, nameAndTypeIndex);
469        return computeIfAbsent(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature, ret);
470    }
471
472    /**
473     * Add a new NameAndType constant to the ConstantPool if it is not already in there.
474     *
475     * @param name Name string to add
476     * @param signature signature string to add
477     * @return index of entry
478     */
479    public int addNameAndType(final String name, final String signature) {
480        int ret;
481        if ((ret = lookupNameAndType(name, signature)) != -1) {
482            return ret; // Already in CP
483        }
484        adjustSize();
485        final int nameIndex = addUtf8(name);
486        final int signatureIndex = addUtf8(signature);
487        ret = index;
488        constants[index++] = new ConstantNameAndType(nameIndex, signatureIndex);
489        return computeIfAbsent(natTable, name + NAT_DELIM + signature, ret);
490    }
491
492    /**
493     * Add a new String constant to the ConstantPool, if it is not already in there.
494     *
495     * @param str String to add
496     * @return index of entry
497     */
498    public int addString(final String str) {
499        int ret;
500        if ((ret = lookupString(str)) != -1) {
501            return ret; // Already in CP
502        }
503        final int utf8 = addUtf8(str);
504        adjustSize();
505        final ConstantString s = new ConstantString(utf8);
506        ret = index;
507        constants[index++] = s;
508        return computeIfAbsent(stringTable, str, ret);
509    }
510
511    /**
512     * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
513     *
514     * @param n Utf8 string to add
515     * @return index of entry
516     */
517    public int addUtf8(final String n) {
518        int ret;
519        if ((ret = lookupUtf8(n)) != -1) {
520            return ret; // Already in CP
521        }
522        adjustSize();
523        ret = index;
524        constants[index++] = new ConstantUtf8(n);
525        return computeIfAbsent(utf8Table, n, ret);
526    }
527
528    /**
529     * Resize internal array of constants.
530     */
531    protected void adjustSize() {
532        // 3 extra spaces are needed as some entries may take 3 slots
533        if (index + 3 >= Const.MAX_CP_ENTRIES + 1) {
534            throw new IllegalStateException("The number of constants " + (index + 3)
535                    + " is over the size of the constant pool: "
536                    + Const.MAX_CP_ENTRIES);
537        }
538
539        if (index + 3 >= size) {
540            final Constant[] tmp = constants;
541            size *= 2;
542            // the constant array shall not exceed the size of the constant pool
543            size = Math.min(size, Const.MAX_CP_ENTRIES + 1);
544            constants = new Constant[size];
545            System.arraycopy(tmp, 0, constants, 0, index);
546        }
547    }
548
549    private int computeIfAbsent(final Map<String, Integer> map, final String key, final int value) {
550        return map.computeIfAbsent(key, k -> Integer.valueOf(value));
551    }
552
553    /**
554     * @param i index in constant pool
555     * @return constant pool entry at index i
556     */
557    public Constant getConstant(final int i) {
558        return constants[i];
559    }
560
561    /**
562     * @return intermediate constant pool
563     */
564    public ConstantPool getConstantPool() {
565        return new ConstantPool(constants);
566    }
567
568    /**
569     * @return constant pool with proper length
570     */
571    public ConstantPool getFinalConstantPool() {
572        return new ConstantPool(Arrays.copyOf(constants, index));
573    }
574
575    private int getIndex(final Map<String, Integer> map, final String key) {
576        return toIndex(map.get(key));
577    }
578
579    /**
580     * @return current size of constant pool
581     */
582    public int getSize() {
583        return index;
584    }
585
586    /**
587     * Look for ConstantClass in ConstantPool named 'str'.
588     *
589     * @param str String to search for
590     * @return index on success, -1 otherwise
591     */
592    public int lookupClass(final String str) {
593        return getIndex(classTable, Utility.packageToPath(str));
594    }
595
596    /**
597     * Look for ConstantDouble in ConstantPool.
598     *
599     * @param n Double number to look for
600     * @return index on success, -1 otherwise
601     */
602    public int lookupDouble(final double n) {
603        final long bits = Double.doubleToLongBits(n);
604        for (int i = 1; i < index; i++) {
605            if (constants[i] instanceof ConstantDouble) {
606                final ConstantDouble c = (ConstantDouble) constants[i];
607                if (Double.doubleToLongBits(c.getBytes()) == bits) {
608                    return i;
609                }
610            }
611        }
612        return -1;
613    }
614
615    /**
616     * Look for ConstantFieldref in ConstantPool.
617     *
618     * @param className Where to find method
619     * @param fieldName Guess what
620     * @param signature return and argument types
621     * @return index on success, -1 otherwise
622     */
623    public int lookupFieldref(final String className, final String fieldName, final String signature) {
624        return getIndex(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature);
625    }
626
627    /**
628     * Look for ConstantFloat in ConstantPool.
629     *
630     * @param n Float number to look for
631     * @return index on success, -1 otherwise
632     */
633    public int lookupFloat(final float n) {
634        final int bits = Float.floatToIntBits(n);
635        for (int i = 1; i < index; i++) {
636            if (constants[i] instanceof ConstantFloat) {
637                final ConstantFloat c = (ConstantFloat) constants[i];
638                if (Float.floatToIntBits(c.getBytes()) == bits) {
639                    return i;
640                }
641            }
642        }
643        return -1;
644    }
645
646    /**
647     * Look for ConstantInteger in ConstantPool.
648     *
649     * @param n integer number to look for
650     * @return index on success, -1 otherwise
651     */
652    public int lookupInteger(final int n) {
653        for (int i = 1; i < index; i++) {
654            if (constants[i] instanceof ConstantInteger) {
655                final ConstantInteger c = (ConstantInteger) constants[i];
656                if (c.getBytes() == n) {
657                    return i;
658                }
659            }
660        }
661        return -1;
662    }
663
664    public int lookupInterfaceMethodref(final MethodGen method) {
665        return lookupInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
666    }
667
668    /**
669     * Look for ConstantInterfaceMethodref in ConstantPool.
670     *
671     * @param className Where to find method
672     * @param methodName Guess what
673     * @param signature return and argument types
674     * @return index on success, -1 otherwise
675     */
676    public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) {
677        return getIndex(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature);
678    }
679
680    /**
681     * Look for ConstantLong in ConstantPool.
682     *
683     * @param n Long number to look for
684     * @return index on success, -1 otherwise
685     */
686    public int lookupLong(final long n) {
687        for (int i = 1; i < index; i++) {
688            if (constants[i] instanceof ConstantLong) {
689                final ConstantLong c = (ConstantLong) constants[i];
690                if (c.getBytes() == n) {
691                    return i;
692                }
693            }
694        }
695        return -1;
696    }
697
698    public int lookupMethodref(final MethodGen method) {
699        return lookupMethodref(method.getClassName(), method.getName(), method.getSignature());
700    }
701
702    /**
703     * Look for ConstantMethodref in ConstantPool.
704     *
705     * @param className Where to find method
706     * @param methodName Guess what
707     * @param signature return and argument types
708     * @return index on success, -1 otherwise
709     */
710    public int lookupMethodref(final String className, final String methodName, final String signature) {
711        return getIndex(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature);
712    }
713
714    /**
715     * Look for ConstantNameAndType in ConstantPool.
716     *
717     * @param name of variable/method
718     * @param signature of variable/method
719     * @return index on success, -1 otherwise
720     */
721    public int lookupNameAndType(final String name, final String signature) {
722        return getIndex(natTable, name + NAT_DELIM + signature);
723    }
724
725    /**
726     * Look for ConstantString in ConstantPool containing String 'str'.
727     *
728     * @param str String to search for
729     * @return index on success, -1 otherwise
730     */
731    public int lookupString(final String str) {
732        return getIndex(stringTable, str);
733    }
734
735    /**
736     * Look for ConstantUtf8 in ConstantPool.
737     *
738     * @param n Utf8 string to look for
739     * @return index on success, -1 otherwise
740     */
741    public int lookupUtf8(final String n) {
742        return getIndex(utf8Table, n);
743    }
744
745    /**
746     * Use with care!
747     *
748     * @param i index in constant pool
749     * @param c new constant pool entry at index i
750     */
751    public void setConstant(final int i, final Constant c) {
752        constants[i] = c;
753    }
754
755    private int toIndex(final Integer index) {
756        return index != null ? index.intValue() : -1;
757    }
758
759    /**
760     * @return String representation.
761     */
762    @Override
763    public String toString() {
764        final StringBuilder buf = new StringBuilder();
765        for (int i = 1; i < index; i++) {
766            buf.append(i).append(")").append(constants[i]).append("\n");
767        }
768        return buf.toString();
769    }
770}