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