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