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