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