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