    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}