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