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 * @version $Id: ConstantPoolGen.java 1806200 2017-08-25 16:33:06Z ggregory $
051 * @see Constant
052 */
053public class ConstantPoolGen {
054
055    private static final int DEFAULT_BUFFER_SIZE = 256;
056
057    /**
058     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
059     */
060    @Deprecated
061    protected int size;
062
063    /**
064     * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
065     */
066    @Deprecated
067    protected Constant[] constants;
068
069    /**
070     * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
071     */
072    @Deprecated
073    protected int index = 1; // First entry (0) used by JVM
074
075    private static final String METHODREF_DELIM = ":";
076    private static final String IMETHODREF_DELIM = "#";
077    private static final String FIELDREF_DELIM = "&";
078    private static final String NAT_DELIM = "%"; // Name and Type
079
080    private static class Index {
081
082        final int index;
083
084
085        Index(final int i) {
086            index = i;
087        }
088    }
089
090
091    /**
092     * Initialize with given array of constants.
093     *
094     * @param cs array of given constants, new ones will be appended
095     */
096    public ConstantPoolGen(final Constant[] cs) {
097        final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE);
098
099        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}