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.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), Const.MAX_CP_ENTRIES + 1);
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 (!stringTable.containsKey(key)) {
114                    stringTable.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 (!classTable.containsKey(key)) {
121                    classTable.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 (!natTable.containsKey(key)) {
135                    natTable.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 (!utf8Table.containsKey(key)) {
141                    utf8Table.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 (!cpTable.containsKey(key)) {
180                    cpTable.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        // 3 extra spaces are needed as some entries may take 3 slots
228        if (index + 3 >= Const.MAX_CP_ENTRIES + 1) {
229            throw new IllegalStateException("The number of constants " + (index + 3)
230                    + " is over the size of the constant pool: "
231                    + Const.MAX_CP_ENTRIES);
232        }
233
234        if (index + 3 >= size) {
235            final Constant[] cs = constants;
236            size *= 2;
237            // the constant array shall not exceed the size of the constant pool
238            size = Math.min(size, Const.MAX_CP_ENTRIES + 1);
239            constants = new Constant[size];
240            System.arraycopy(cs, 0, constants, 0, index);
241        }
242    }
243
244    private final Map<String, Index> stringTable = new HashMap<>();
245
246
247    /**
248     * Look for ConstantString in ConstantPool containing String `str'.
249     *
250     * @param str String to search for
251     * @return index on success, -1 otherwise
252     */
253    public int lookupString( final String str ) {
254        final Index index = stringTable.get(str);
255        return (index != null) ? index.index : -1;
256    }
257
258
259    /**
260     * Add a new String constant to the ConstantPool, if it is not already in there.
261     *
262     * @param str String to add
263     * @return index of entry
264     */
265    public int addString( final String str ) {
266        int ret;
267        if ((ret = lookupString(str)) != -1) {
268            return ret; // Already in CP
269        }
270        final int utf8 = addUtf8(str);
271        adjustSize();
272        final ConstantString s = new ConstantString(utf8);
273        ret = index;
274        constants[index++] = s;
275        if (!stringTable.containsKey(str)) {
276            stringTable.put(str, new Index(ret));
277        }
278        return ret;
279    }
280
281    private final Map<String, Index> classTable = new HashMap<>();
282
283
284    /**
285     * Look for ConstantClass in ConstantPool named `str'.
286     *
287     * @param str String to search for
288     * @return index on success, -1 otherwise
289     */
290    public int lookupClass( final String str ) {
291        final Index index = classTable.get(str.replace('.', '/'));
292        return (index != null) ? index.index : -1;
293    }
294
295
296    private int addClass_( final String clazz ) {
297        int ret;
298        if ((ret = lookupClass(clazz)) != -1) {
299            return ret; // Already in CP
300        }
301        adjustSize();
302        final ConstantClass c = new ConstantClass(addUtf8(clazz));
303        ret = index;
304        constants[index++] = c;
305        if (!classTable.containsKey(clazz)) {
306            classTable.put(clazz, new Index(ret));
307        }
308        return ret;
309    }
310
311
312    /**
313     * Add a new Class reference to the ConstantPool, if it is not already in there.
314     *
315     * @param str Class to add
316     * @return index of entry
317     */
318    public int addClass( final String str ) {
319        return addClass_(str.replace('.', '/'));
320    }
321
322
323    /**
324     * Add a new Class reference to the ConstantPool for a given type.
325     *
326     * @param type Class to add
327     * @return index of entry
328     */
329    public int addClass( final ObjectType type ) {
330        return addClass(type.getClassName());
331    }
332
333
334    /**
335     * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY
336     * instruction, e.g. to the ConstantPool.
337     *
338     * @param type type of array class
339     * @return index of entry
340     */
341    public int addArrayClass( final ArrayType type ) {
342        return addClass_(type.getSignature());
343    }
344
345
346    /**
347     * Look for ConstantInteger in ConstantPool.
348     *
349     * @param n integer number to look for
350     * @return index on success, -1 otherwise
351     */
352    public int lookupInteger( final int n ) {
353        for (int i = 1; i < index; i++) {
354            if (constants[i] instanceof ConstantInteger) {
355                final ConstantInteger c = (ConstantInteger) constants[i];
356                if (c.getBytes() == n) {
357                    return i;
358                }
359            }
360        }
361        return -1;
362    }
363
364
365    /**
366     * Add a new Integer constant to the ConstantPool, if it is not already in there.
367     *
368     * @param n integer number to add
369     * @return index of entry
370     */
371    public int addInteger( final int n ) {
372        int ret;
373        if ((ret = lookupInteger(n)) != -1) {
374            return ret; // Already in CP
375        }
376        adjustSize();
377        ret = index;
378        constants[index++] = new ConstantInteger(n);
379        return ret;
380    }
381
382
383    /**
384     * Look for ConstantFloat in ConstantPool.
385     *
386     * @param n Float number to look for
387     * @return index on success, -1 otherwise
388     */
389    public int lookupFloat( final float n ) {
390        final int bits = Float.floatToIntBits(n);
391        for (int i = 1; i < index; i++) {
392            if (constants[i] instanceof ConstantFloat) {
393                final ConstantFloat c = (ConstantFloat) constants[i];
394                if (Float.floatToIntBits(c.getBytes()) == bits) {
395                    return i;
396                }
397            }
398        }
399        return -1;
400    }
401
402
403    /**
404     * Add a new Float constant to the ConstantPool, if it is not already in there.
405     *
406     * @param n Float number to add
407     * @return index of entry
408     */
409    public int addFloat( final float n ) {
410        int ret;
411        if ((ret = lookupFloat(n)) != -1) {
412            return ret; // Already in CP
413        }
414        adjustSize();
415        ret = index;
416        constants[index++] = new ConstantFloat(n);
417        return ret;
418    }
419
420    private final Map<String, Index> utf8Table = new HashMap<>();
421
422
423    /**
424     * Look for ConstantUtf8 in ConstantPool.
425     *
426     * @param n Utf8 string to look for
427     * @return index on success, -1 otherwise
428     */
429    public int lookupUtf8( final String n ) {
430        final Index index = utf8Table.get(n);
431        return (index != null) ? index.index : -1;
432    }
433
434
435    /**
436     * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
437     *
438     * @param n Utf8 string to add
439     * @return index of entry
440     */
441    public int addUtf8( final String n ) {
442        int ret;
443        if ((ret = lookupUtf8(n)) != -1) {
444            return ret; // Already in CP
445        }
446        adjustSize();
447        ret = index;
448        constants[index++] = new ConstantUtf8(n);
449        if (!utf8Table.containsKey(n)) {
450            utf8Table.put(n, new Index(ret));
451        }
452        return ret;
453    }
454
455
456    /**
457     * Look for ConstantLong in ConstantPool.
458     *
459     * @param n Long number to look for
460     * @return index on success, -1 otherwise
461     */
462    public int lookupLong( final long n ) {
463        for (int i = 1; i < index; i++) {
464            if (constants[i] instanceof ConstantLong) {
465                final ConstantLong c = (ConstantLong) constants[i];
466                if (c.getBytes() == n) {
467                    return i;
468                }
469            }
470        }
471        return -1;
472    }
473
474
475    /**
476     * Add a new long constant to the ConstantPool, if it is not already in there.
477     *
478     * @param n Long number to add
479     * @return index of entry
480     */
481    public int addLong( final long n ) {
482        int ret;
483        if ((ret = lookupLong(n)) != -1) {
484            return ret; // Already in CP
485        }
486        adjustSize();
487        ret = index;
488        constants[index] = new ConstantLong(n);
489        index += 2; // Wastes one entry according to spec
490        return ret;
491    }
492
493
494    /**
495     * Look for ConstantDouble in ConstantPool.
496     *
497     * @param n Double number to look for
498     * @return index on success, -1 otherwise
499     */
500    public int lookupDouble( final double n ) {
501        final long bits = Double.doubleToLongBits(n);
502        for (int i = 1; i < index; i++) {
503            if (constants[i] instanceof ConstantDouble) {
504                final ConstantDouble c = (ConstantDouble) constants[i];
505                if (Double.doubleToLongBits(c.getBytes()) == bits) {
506                    return i;
507                }
508            }
509        }
510        return -1;
511    }
512
513
514    /**
515     * Add a new double constant to the ConstantPool, if it is not already in there.
516     *
517     * @param n Double number to add
518     * @return index of entry
519     */
520    public int addDouble( final double n ) {
521        int ret;
522        if ((ret = lookupDouble(n)) != -1) {
523            return ret; // Already in CP
524        }
525        adjustSize();
526        ret = index;
527        constants[index] = new ConstantDouble(n);
528        index += 2; // Wastes one entry according to spec
529        return ret;
530    }
531
532    private final Map<String, Index> natTable = new HashMap<>();
533
534
535    /**
536     * Look for ConstantNameAndType in ConstantPool.
537     *
538     * @param name of variable/method
539     * @param signature of variable/method
540     * @return index on success, -1 otherwise
541     */
542    public int lookupNameAndType( final String name, final String signature ) {
543        final Index _index = natTable.get(name + NAT_DELIM + signature);
544        return (_index != null) ? _index.index : -1;
545    }
546
547
548    /**
549     * Add a new NameAndType constant to the ConstantPool if it is not already
550     * in there.
551     *
552     * @param name Name string to add
553     * @param signature signature string to add
554     * @return index of entry
555     */
556    public int addNameAndType( final String name, final String signature ) {
557        int ret;
558        int name_index;
559        int signature_index;
560        if ((ret = lookupNameAndType(name, signature)) != -1) {
561            return ret; // Already in CP
562        }
563        adjustSize();
564        name_index = addUtf8(name);
565        signature_index = addUtf8(signature);
566        ret = index;
567        constants[index++] = new ConstantNameAndType(name_index, signature_index);
568        final String key = name + NAT_DELIM + signature;
569        if (!natTable.containsKey(key)) {
570            natTable.put(key, new Index(ret));
571        }
572        return ret;
573    }
574
575    private final Map<String, Index> cpTable = new HashMap<>();
576
577
578    /**
579     * Look for ConstantMethodref in ConstantPool.
580     *
581     * @param class_name Where to find method
582     * @param method_name Guess what
583     * @param signature return and argument types
584     * @return index on success, -1 otherwise
585     */
586    public int lookupMethodref( final String class_name, final String method_name, final String signature ) {
587        final Index index = cpTable.get(class_name + METHODREF_DELIM + method_name
588                + METHODREF_DELIM + signature);
589        return (index != null) ? index.index : -1;
590    }
591
592
593    public int lookupMethodref( final MethodGen method ) {
594        return lookupMethodref(method.getClassName(), method.getName(), method.getSignature());
595    }
596
597
598    /**
599     * Add a new Methodref constant to the ConstantPool, if it is not already
600     * in there.
601     *
602     * @param class_name class name string to add
603     * @param method_name method name string to add
604     * @param signature method signature string to add
605     * @return index of entry
606     */
607    public int addMethodref( final String class_name, final String method_name, final String signature ) {
608        int ret;
609        int class_index;
610        int name_and_type_index;
611        if ((ret = lookupMethodref(class_name, method_name, signature)) != -1) {
612            return ret; // Already in CP
613        }
614        adjustSize();
615        name_and_type_index = addNameAndType(method_name, signature);
616        class_index = addClass(class_name);
617        ret = index;
618        constants[index++] = new ConstantMethodref(class_index, name_and_type_index);
619        final String key = class_name + METHODREF_DELIM + method_name + METHODREF_DELIM + signature;
620        if (!cpTable.containsKey(key)) {
621            cpTable.put(key, new Index(ret));
622        }
623        return ret;
624    }
625
626
627    public int addMethodref( final MethodGen method ) {
628        return addMethodref(method.getClassName(), method.getName(), method.getSignature());
629    }
630
631
632    /**
633     * Look for ConstantInterfaceMethodref in ConstantPool.
634     *
635     * @param class_name Where to find method
636     * @param method_name Guess what
637     * @param signature return and argument types
638     * @return index on success, -1 otherwise
639     */
640    public int lookupInterfaceMethodref( final String class_name, final String method_name, final String signature ) {
641        final Index index = cpTable.get(class_name + IMETHODREF_DELIM + method_name
642                + IMETHODREF_DELIM + signature);
643        return (index != null) ? index.index : -1;
644    }
645
646
647    public int lookupInterfaceMethodref( final MethodGen method ) {
648        return lookupInterfaceMethodref(method.getClassName(), method.getName(), method
649                .getSignature());
650    }
651
652
653    /**
654     * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already
655     * in there.
656     *
657     * @param class_name class name string to add
658     * @param method_name method name string to add
659     * @param signature signature string to add
660     * @return index of entry
661     */
662    public int addInterfaceMethodref( final String class_name, final String method_name, final String signature ) {
663        int ret;
664        int class_index;
665        int name_and_type_index;
666        if ((ret = lookupInterfaceMethodref(class_name, method_name, signature)) != -1) {
667            return ret; // Already in CP
668        }
669        adjustSize();
670        class_index = addClass(class_name);
671        name_and_type_index = addNameAndType(method_name, signature);
672        ret = index;
673        constants[index++] = new ConstantInterfaceMethodref(class_index, name_and_type_index);
674        final String key = class_name + IMETHODREF_DELIM + method_name + IMETHODREF_DELIM + signature;
675        if (!cpTable.containsKey(key)) {
676            cpTable.put(key, new Index(ret));
677        }
678        return ret;
679    }
680
681
682    public int addInterfaceMethodref( final MethodGen method ) {
683        return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
684    }
685
686
687    /**
688     * Look for ConstantFieldref in ConstantPool.
689     *
690     * @param class_name Where to find method
691     * @param field_name Guess what
692     * @param signature return and argument types
693     * @return index on success, -1 otherwise
694     */
695    public int lookupFieldref( final String class_name, final String field_name, final String signature ) {
696        final Index index = cpTable.get(class_name + FIELDREF_DELIM + field_name
697                + FIELDREF_DELIM + signature);
698        return (index != null) ? index.index : -1;
699    }
700
701
702    /**
703     * Add a new Fieldref constant to the ConstantPool, if it is not already
704     * in there.
705     *
706     * @param class_name class name string to add
707     * @param field_name field name string to add
708     * @param signature signature string to add
709     * @return index of entry
710     */
711    public int addFieldref( final String class_name, final String field_name, final String signature ) {
712        int ret;
713        int class_index;
714        int name_and_type_index;
715        if ((ret = lookupFieldref(class_name, field_name, signature)) != -1) {
716            return ret; // Already in CP
717        }
718        adjustSize();
719        class_index = addClass(class_name);
720        name_and_type_index = addNameAndType(field_name, signature);
721        ret = index;
722        constants[index++] = new ConstantFieldref(class_index, name_and_type_index);
723        final String key = class_name + FIELDREF_DELIM + field_name + FIELDREF_DELIM + signature;
724        if (!cpTable.containsKey(key)) {
725            cpTable.put(key, new Index(ret));
726        }
727        return ret;
728    }
729
730
731    /**
732     * @param i index in constant pool
733     * @return constant pool entry at index i
734     */
735    public Constant getConstant( final int i ) {
736        return constants[i];
737    }
738
739
740    /**
741     * Use with care!
742     *
743     * @param i index in constant pool
744     * @param c new constant pool entry at index i
745     */
746    public void setConstant( final int i, final Constant c ) {
747        constants[i] = c;
748    }
749
750
751    /**
752     * @return intermediate constant pool
753     */
754    public ConstantPool getConstantPool() {
755        return new ConstantPool(constants);
756    }
757
758
759    /**
760     * @return current size of constant pool
761     */
762    public int getSize() {
763        return index;
764    }
765
766
767    /**
768     * @return constant pool with proper length
769     */
770    public ConstantPool getFinalConstantPool() {
771        final Constant[] cs = new Constant[index];
772        System.arraycopy(constants, 0, cs, 0, index);
773        return new ConstantPool(cs);
774    }
775
776
777    /**
778     * @return String representation.
779     */
780    @Override
781    public String toString() {
782        final StringBuilder buf = new StringBuilder();
783        for (int i = 1; i < index; i++) {
784            buf.append(i).append(")").append(constants[i]).append("\n");
785        }
786        return buf.toString();
787    }
788
789
790    /** Import constant from another ConstantPool and return new index.
791     */
792    public int addConstant( final Constant c, final ConstantPoolGen cp ) {
793        final Constant[] constants = cp.getConstantPool().getConstantPool();
794        switch (c.getTag()) {
795            case Const.CONSTANT_String: {
796                final ConstantString s = (ConstantString) c;
797                final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
798                return addString(u8.getBytes());
799            }
800            case Const.CONSTANT_Class: {
801                final ConstantClass s = (ConstantClass) c;
802                final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
803                return addClass(u8.getBytes());
804            }
805            case Const.CONSTANT_NameAndType: {
806                final ConstantNameAndType n = (ConstantNameAndType) c;
807                final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
808                final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
809                return addNameAndType(u8.getBytes(), u8_2.getBytes());
810            }
811            case Const.CONSTANT_Utf8:
812                return addUtf8(((ConstantUtf8) c).getBytes());
813            case Const.CONSTANT_Double:
814                return addDouble(((ConstantDouble) c).getBytes());
815            case Const.CONSTANT_Float:
816                return addFloat(((ConstantFloat) c).getBytes());
817            case Const.CONSTANT_Long:
818                return addLong(((ConstantLong) c).getBytes());
819            case Const.CONSTANT_Integer:
820                return addInteger(((ConstantInteger) c).getBytes());
821            case Const.CONSTANT_InterfaceMethodref:
822            case Const.CONSTANT_Methodref:
823            case Const.CONSTANT_Fieldref: {
824                final ConstantCP m = (ConstantCP) c;
825                final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
826                final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
827                ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
828                final String class_name = u8.getBytes().replace('/', '.');
829                u8 = (ConstantUtf8) constants[n.getNameIndex()];
830                final String name = u8.getBytes();
831                u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
832                final String signature = u8.getBytes();
833                switch (c.getTag()) {
834                    case Const.CONSTANT_InterfaceMethodref:
835                        return addInterfaceMethodref(class_name, name, signature);
836                    case Const.CONSTANT_Methodref:
837                        return addMethodref(class_name, name, signature);
838                    case Const.CONSTANT_Fieldref:
839                        return addFieldref(class_name, name, signature);
840                    default: // Never reached
841                        throw new IllegalArgumentException("Unknown constant type " + c);
842                }
843            }
844            default: // Never reached
845                throw new IllegalArgumentException("Unknown constant type " + c);
846        }
847    }
848}