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      /**
63       * Builds a lookup key that stays collision-free even when the parts contain the ASCII characters used as
64       * delimiters above. Class, member and signature names read from a class file may legally contain those characters
65       * (the JVMS only forbids {@code . ; [ /} and, for members, {@code < >}), so each part is prefixed with its length
66       * to keep distinct triples distinct.
67       *
68       * @param parts The key parts.
69       * @return A collision-free key.
70       */
71      private static String toKey(final String... parts) {
72          final StringBuilder buf = new StringBuilder();
73          for (final String part : parts) {
74              buf.append(part.length()).append(':').append(part);
75          }
76          return buf.toString();
77      }
78  
79      /**
80       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
81       */
82      @Deprecated
83      protected int size;
84  
85      /**
86       * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
87       */
88      @Deprecated
89      protected Constant[] constants;
90  
91      /**
92       * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
93       */
94      @Deprecated
95      protected int index = 1; // First entry (0) used by JVM
96  
97      private final Map<String, Integer> stringTable = new HashMap<>();
98  
99      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 }