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