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