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