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