ConstantPoolGen.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */
  17. package org.apache.bcel.generic;

  18. import java.util.Arrays;
  19. import java.util.HashMap;
  20. import java.util.Map;

  21. import org.apache.bcel.Const;
  22. import org.apache.bcel.classfile.Constant;
  23. import org.apache.bcel.classfile.ConstantCP;
  24. import org.apache.bcel.classfile.ConstantClass;
  25. import org.apache.bcel.classfile.ConstantDouble;
  26. import org.apache.bcel.classfile.ConstantDynamic;
  27. import org.apache.bcel.classfile.ConstantFieldref;
  28. import org.apache.bcel.classfile.ConstantFloat;
  29. import org.apache.bcel.classfile.ConstantInteger;
  30. import org.apache.bcel.classfile.ConstantInterfaceMethodref;
  31. import org.apache.bcel.classfile.ConstantInvokeDynamic;
  32. import org.apache.bcel.classfile.ConstantLong;
  33. import org.apache.bcel.classfile.ConstantMethodref;
  34. import org.apache.bcel.classfile.ConstantNameAndType;
  35. import org.apache.bcel.classfile.ConstantPool;
  36. import org.apache.bcel.classfile.ConstantString;
  37. import org.apache.bcel.classfile.ConstantUtf8;
  38. import org.apache.bcel.classfile.Utility;

  39. /**
  40.  * This class is used to build up a constant pool. The user adds constants via 'addXXX' methods, 'addString',
  41.  * 'addClass', etc.. These methods return an index into the constant pool. Finally, 'getFinalConstantPool()' returns the
  42.  * constant pool built up. Intermediate versions of the constant pool can be obtained with 'getConstantPool()'. A
  43.  * constant pool has capacity for Constants.MAX_SHORT entries. Note that the first (0) is used by the JVM and that
  44.  * Double and Long constants need two slots.
  45.  *
  46.  * @see Constant
  47.  */
  48. public class ConstantPoolGen {

  49.     private static final int DEFAULT_BUFFER_SIZE = 256;

  50.     private static final String METHODREF_DELIM = ":";

  51.     private static final String IMETHODREF_DELIM = "#";

  52.     private static final String FIELDREF_DELIM = "&";

  53.     private static final String NAT_DELIM = "%"; // Name and Type

  54.     /**
  55.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  56.      */
  57.     @Deprecated
  58.     protected int size;

  59.     /**
  60.      * @deprecated (since 6.0) will be made private; do not access directly, use getter/setter
  61.      */
  62.     @Deprecated
  63.     protected Constant[] constants;

  64.     /**
  65.      * @deprecated (since 6.0) will be made private; do not access directly, use getSize()
  66.      */
  67.     @Deprecated
  68.     protected int index = 1; // First entry (0) used by JVM

  69.     private final Map<String, Integer> stringTable = new HashMap<>();

  70.     private final Map<String, Integer> classTable = new HashMap<>();

  71.     private final Map<String, Integer> utf8Table = new HashMap<>();

  72.     private final Map<String, Integer> natTable = new HashMap<>();

  73.     private final Map<String, Integer> cpTable = new HashMap<>();

  74.     /**
  75.      * Constructs a new empty constant pool.
  76.      */
  77.     public ConstantPoolGen() {
  78.         size = DEFAULT_BUFFER_SIZE;
  79.         constants = new Constant[size];
  80.     }

  81.     /**
  82.      * Constructs a new instance with the given array of constants.
  83.      *
  84.      * @param cs array of given constants, new ones will be appended
  85.      */
  86.     public ConstantPoolGen(final Constant[] cs) {
  87.         final StringBuilder sb = new StringBuilder(DEFAULT_BUFFER_SIZE);

  88.         size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), Const.MAX_CP_ENTRIES + 1);
  89.         constants = Arrays.copyOf(cs, size);

  90.         if (cs.length > 0) {
  91.             index = cs.length;
  92.         }

  93.         for (int i = 1; i < index; i++) {
  94.             final Constant c = constants[i];
  95.             if (c instanceof ConstantString) {
  96.                 final ConstantString s = (ConstantString) c;
  97.                 final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
  98.                 final String key = u8.getBytes();
  99.                 if (!stringTable.containsKey(key)) {
  100.                     stringTable.put(key, Integer.valueOf(i));
  101.                 }
  102.             } else if (c instanceof ConstantClass) {
  103.                 final ConstantClass s = (ConstantClass) c;
  104.                 final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
  105.                 final String key = u8.getBytes();
  106.                 if (!classTable.containsKey(key)) {
  107.                     classTable.put(key, Integer.valueOf(i));
  108.                 }
  109.             } else if (c instanceof ConstantNameAndType) {
  110.                 final ConstantNameAndType n = (ConstantNameAndType) c;
  111.                 final ConstantUtf8 u8NameIdx = (ConstantUtf8) constants[n.getNameIndex()];
  112.                 final ConstantUtf8 u8SigIdx = (ConstantUtf8) constants[n.getSignatureIndex()];

  113.                 sb.append(u8NameIdx.getBytes());
  114.                 sb.append(NAT_DELIM);
  115.                 sb.append(u8SigIdx.getBytes());
  116.                 final String key = sb.toString();
  117.                 sb.delete(0, sb.length());

  118.                 if (!natTable.containsKey(key)) {
  119.                     natTable.put(key, Integer.valueOf(i));
  120.                 }
  121.             } else if (c instanceof ConstantUtf8) {
  122.                 final ConstantUtf8 u = (ConstantUtf8) c;
  123.                 final String key = u.getBytes();
  124.                 if (!utf8Table.containsKey(key)) {
  125.                     utf8Table.put(key, Integer.valueOf(i));
  126.                 }
  127.             } else if (c instanceof ConstantCP) {
  128.                 final ConstantCP m = (ConstantCP) c;
  129.                 String className;
  130.                 ConstantUtf8 u8;

  131.                 if (c instanceof ConstantInvokeDynamic) {
  132.                     className = Integer.toString(((ConstantInvokeDynamic) m).getBootstrapMethodAttrIndex());
  133.                 } else if (c instanceof ConstantDynamic) {
  134.                     className = Integer.toString(((ConstantDynamic) m).getBootstrapMethodAttrIndex());
  135.                 } else {
  136.                     final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
  137.                     u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
  138.                     className = Utility.pathToPackage(u8.getBytes());
  139.                 }

  140.                 final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
  141.                 u8 = (ConstantUtf8) constants[n.getNameIndex()];
  142.                 final String methodName = u8.getBytes();
  143.                 u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
  144.                 final String signature = u8.getBytes();

  145.                 // Since name cannot begin with digit, we can use METHODREF_DELIM without fear of duplicates
  146.                 String delim = METHODREF_DELIM;
  147.                 if (c instanceof ConstantInterfaceMethodref) {
  148.                     delim = IMETHODREF_DELIM;
  149.                 } else if (c instanceof ConstantFieldref) {
  150.                     delim = FIELDREF_DELIM;
  151.                 }

  152.                 sb.append(className);
  153.                 sb.append(delim);
  154.                 sb.append(methodName);
  155.                 sb.append(delim);
  156.                 sb.append(signature);
  157.                 final String key = sb.toString();
  158.                 sb.delete(0, sb.length());

  159.                 if (!cpTable.containsKey(key)) {
  160.                     cpTable.put(key, Integer.valueOf(i));
  161.                 }
  162.             }
  163. //            else if (c == null) { // entries may be null
  164. //                // nothing to do
  165. //            } else if (c instanceof ConstantInteger) {
  166. //                // nothing to do
  167. //            } else if (c instanceof ConstantLong) {
  168. //                // nothing to do
  169. //            } else if (c instanceof ConstantFloat) {
  170. //                // nothing to do
  171. //            } else if (c instanceof ConstantDouble) {
  172. //                // nothing to do
  173. //            } else if (c instanceof org.apache.bcel.classfile.ConstantMethodType) {
  174. //                // TODO should this be handled somehow?
  175. //            } else if (c instanceof org.apache.bcel.classfile.ConstantMethodHandle) {
  176. //                // TODO should this be handled somehow?
  177. //            } else if (c instanceof org.apache.bcel.classfile.ConstantModule) {
  178. //                // TODO should this be handled somehow?
  179. //            } else if (c instanceof org.apache.bcel.classfile.ConstantPackage) {
  180. //                // TODO should this be handled somehow?
  181. //            } else {
  182. //                // Not helpful, should throw an exception.
  183. //                assert false : "Unexpected constant type: " + c.getClass().getName();
  184. //            }
  185.         }
  186.     }

  187.     /**
  188.      * Constructs a new instance with the given constant pool.
  189.      *
  190.      * @param cp the constant pool.
  191.      */
  192.     public ConstantPoolGen(final ConstantPool cp) {
  193.         this(cp.getConstantPool());
  194.     }

  195.     /**
  196.      * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY instruction, e.g. to the
  197.      * ConstantPool.
  198.      *
  199.      * @param type type of array class
  200.      * @return index of entry
  201.      */
  202.     public int addArrayClass(final ArrayType type) {
  203.         return addClass_(type.getSignature());
  204.     }

  205.     /**
  206.      * Add a new Class reference to the ConstantPool for a given type.
  207.      *
  208.      * @param type Class to add
  209.      * @return index of entry
  210.      */
  211.     public int addClass(final ObjectType type) {
  212.         return addClass(type.getClassName());
  213.     }

  214.     /**
  215.      * Add a new Class reference to the ConstantPool, if it is not already in there.
  216.      *
  217.      * @param str Class to add
  218.      * @return index of entry
  219.      */
  220.     public int addClass(final String str) {
  221.         return addClass_(Utility.packageToPath(str));
  222.     }

  223.     private int addClass_(final String clazz) {
  224.         final int cpRet;
  225.         if ((cpRet = lookupClass(clazz)) != -1) {
  226.             return cpRet; // Already in CP
  227.         }
  228.         adjustSize();
  229.         final ConstantClass c = new ConstantClass(addUtf8(clazz));
  230.         final int ret = index;
  231.         constants[index++] = c;
  232.         return computeIfAbsent(classTable, clazz, ret);
  233.     }

  234.     /**
  235.      * Adds a constant from another ConstantPool and returns the new index.
  236.      *
  237.      * @param constant The constant to add.
  238.      * @param cpGen Source pool.
  239.      * @return index of entry
  240.      */
  241.     public int addConstant(final Constant constant, final ConstantPoolGen cpGen) {
  242.         final Constant[] constants = cpGen.getConstantPool().getConstantPool();
  243.         switch (constant.getTag()) {
  244.         case Const.CONSTANT_String: {
  245.             final ConstantString s = (ConstantString) constant;
  246.             final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getStringIndex()];
  247.             return addString(u8.getBytes());
  248.         }
  249.         case Const.CONSTANT_Class: {
  250.             final ConstantClass s = (ConstantClass) constant;
  251.             final ConstantUtf8 u8 = (ConstantUtf8) constants[s.getNameIndex()];
  252.             return addClass(u8.getBytes());
  253.         }
  254.         case Const.CONSTANT_NameAndType: {
  255.             final ConstantNameAndType n = (ConstantNameAndType) constant;
  256.             final ConstantUtf8 u8 = (ConstantUtf8) constants[n.getNameIndex()];
  257.             final ConstantUtf8 u8_2 = (ConstantUtf8) constants[n.getSignatureIndex()];
  258.             return addNameAndType(u8.getBytes(), u8_2.getBytes());
  259.         }
  260.         case Const.CONSTANT_Utf8:
  261.             return addUtf8(((ConstantUtf8) constant).getBytes());
  262.         case Const.CONSTANT_Double:
  263.             return addDouble(((ConstantDouble) constant).getBytes());
  264.         case Const.CONSTANT_Float:
  265.             return addFloat(((ConstantFloat) constant).getBytes());
  266.         case Const.CONSTANT_Long:
  267.             return addLong(((ConstantLong) constant).getBytes());
  268.         case Const.CONSTANT_Integer:
  269.             return addInteger(((ConstantInteger) constant).getBytes());
  270.         case Const.CONSTANT_InterfaceMethodref:
  271.         case Const.CONSTANT_Methodref:
  272.         case Const.CONSTANT_Fieldref: {
  273.             final ConstantCP m = (ConstantCP) constant;
  274.             final ConstantClass clazz = (ConstantClass) constants[m.getClassIndex()];
  275.             final ConstantNameAndType n = (ConstantNameAndType) constants[m.getNameAndTypeIndex()];
  276.             ConstantUtf8 u8 = (ConstantUtf8) constants[clazz.getNameIndex()];
  277.             final String className = Utility.pathToPackage(u8.getBytes());
  278.             u8 = (ConstantUtf8) constants[n.getNameIndex()];
  279.             final String name = u8.getBytes();
  280.             u8 = (ConstantUtf8) constants[n.getSignatureIndex()];
  281.             final String signature = u8.getBytes();
  282.             switch (constant.getTag()) {
  283.             case Const.CONSTANT_InterfaceMethodref:
  284.                 return addInterfaceMethodref(className, name, signature);
  285.             case Const.CONSTANT_Methodref:
  286.                 return addMethodref(className, name, signature);
  287.             case Const.CONSTANT_Fieldref:
  288.                 return addFieldref(className, name, signature);
  289.             default: // Never reached
  290.                 throw new IllegalArgumentException("Unknown constant type " + constant);
  291.             }
  292.         }
  293.         default: // Never reached
  294.             throw new IllegalArgumentException("Unknown constant type " + constant);
  295.         }
  296.     }

  297.     /**
  298.      * Add a new double constant to the ConstantPool, if it is not already in there.
  299.      *
  300.      * @param n Double number to add
  301.      * @return index of entry
  302.      */
  303.     public int addDouble(final double n) {
  304.         int ret;
  305.         if ((ret = lookupDouble(n)) != -1) {
  306.             return ret; // Already in CP
  307.         }
  308.         adjustSize();
  309.         ret = index;
  310.         constants[index] = new ConstantDouble(n);
  311.         index += 2; // Wastes one entry according to spec
  312.         return ret;
  313.     }

  314.     /**
  315.      * Add a new Fieldref constant to the ConstantPool, if it is not already in there.
  316.      *
  317.      * @param className class name string to add
  318.      * @param fieldName field name string to add
  319.      * @param signature signature string to add
  320.      * @return index of entry
  321.      */
  322.     public int addFieldref(final String className, final String fieldName, final String signature) {
  323.         final int cpRet;
  324.         if ((cpRet = lookupFieldref(className, fieldName, signature)) != -1) {
  325.             return cpRet; // Already in CP
  326.         }
  327.         adjustSize();
  328.         final int classIndex = addClass(className);
  329.         final int nameAndTypeIndex = addNameAndType(fieldName, signature);
  330.         final int ret = index;
  331.         constants[index++] = new ConstantFieldref(classIndex, nameAndTypeIndex);
  332.         return computeIfAbsent(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature, ret);
  333.     }

  334.     /**
  335.      * Add a new Float constant to the ConstantPool, if it is not already in there.
  336.      *
  337.      * @param n Float number to add
  338.      * @return index of entry
  339.      */
  340.     public int addFloat(final float n) {
  341.         int ret;
  342.         if ((ret = lookupFloat(n)) != -1) {
  343.             return ret; // Already in CP
  344.         }
  345.         adjustSize();
  346.         ret = index;
  347.         constants[index++] = new ConstantFloat(n);
  348.         return ret;
  349.     }

  350.     /**
  351.      * Add a new Integer constant to the ConstantPool, if it is not already in there.
  352.      *
  353.      * @param n integer number to add
  354.      * @return index of entry
  355.      */
  356.     public int addInteger(final int n) {
  357.         int ret;
  358.         if ((ret = lookupInteger(n)) != -1) {
  359.             return ret; // Already in CP
  360.         }
  361.         adjustSize();
  362.         ret = index;
  363.         constants[index++] = new ConstantInteger(n);
  364.         return ret;
  365.     }

  366.     public int addInterfaceMethodref(final MethodGen method) {
  367.         return addInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
  368.     }

  369.     /**
  370.      * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already in there.
  371.      *
  372.      * @param className class name string to add
  373.      * @param methodName method name string to add
  374.      * @param signature signature string to add
  375.      * @return index of entry
  376.      */
  377.     public int addInterfaceMethodref(final String className, final String methodName, final String signature) {
  378.         final int cpRet;
  379.         if ((cpRet = lookupInterfaceMethodref(className, methodName, signature)) != -1) {
  380.             return cpRet; // Already in CP
  381.         }
  382.         adjustSize();
  383.         final int classIndex = addClass(className);
  384.         final int nameAndTypeIndex = addNameAndType(methodName, signature);
  385.         final int ret = index;
  386.         constants[index++] = new ConstantInterfaceMethodref(classIndex, nameAndTypeIndex);
  387.         return computeIfAbsent(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature, ret);
  388.     }

  389.     /**
  390.      * Add a new long constant to the ConstantPool, if it is not already in there.
  391.      *
  392.      * @param n Long number to add
  393.      * @return index of entry
  394.      */
  395.     public int addLong(final long n) {
  396.         int ret;
  397.         if ((ret = lookupLong(n)) != -1) {
  398.             return ret; // Already in CP
  399.         }
  400.         adjustSize();
  401.         ret = index;
  402.         constants[index] = new ConstantLong(n);
  403.         index += 2; // Wastes one entry according to spec
  404.         return ret;
  405.     }
  406.     public int addMethodref(final MethodGen method) {
  407.         return addMethodref(method.getClassName(), method.getName(), method.getSignature());
  408.     }

  409.     /**
  410.      * Add a new Methodref constant to the ConstantPool, if it is not already in there.
  411.      *
  412.      * @param className class name string to add
  413.      * @param methodName method name string to add
  414.      * @param signature method signature string to add
  415.      * @return index of entry
  416.      */
  417.     public int addMethodref(final String className, final String methodName, final String signature) {
  418.         final int cpRet;
  419.         if ((cpRet = lookupMethodref(className, methodName, signature)) != -1) {
  420.             return cpRet; // Already in CP
  421.         }
  422.         adjustSize();
  423.         final int nameAndTypeIndex = addNameAndType(methodName, signature);
  424.         final int classIndex = addClass(className);
  425.         final int ret = index;
  426.         constants[index++] = new ConstantMethodref(classIndex, nameAndTypeIndex);
  427.         return computeIfAbsent(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature, ret);
  428.     }

  429.     /**
  430.      * Add a new NameAndType constant to the ConstantPool if it is not already in there.
  431.      *
  432.      * @param name Name string to add
  433.      * @param signature signature string to add
  434.      * @return index of entry
  435.      */
  436.     public int addNameAndType(final String name, final String signature) {
  437.         int ret;
  438.         if ((ret = lookupNameAndType(name, signature)) != -1) {
  439.             return ret; // Already in CP
  440.         }
  441.         adjustSize();
  442.         final int nameIndex = addUtf8(name);
  443.         final int signatureIndex = addUtf8(signature);
  444.         ret = index;
  445.         constants[index++] = new ConstantNameAndType(nameIndex, signatureIndex);
  446.         return computeIfAbsent(natTable, name + NAT_DELIM + signature, ret);
  447.     }

  448.     /**
  449.      * Add a new String constant to the ConstantPool, if it is not already in there.
  450.      *
  451.      * @param str String to add
  452.      * @return index of entry
  453.      */
  454.     public int addString(final String str) {
  455.         int ret;
  456.         if ((ret = lookupString(str)) != -1) {
  457.             return ret; // Already in CP
  458.         }
  459.         final int utf8 = addUtf8(str);
  460.         adjustSize();
  461.         final ConstantString s = new ConstantString(utf8);
  462.         ret = index;
  463.         constants[index++] = s;
  464.         return computeIfAbsent(stringTable, str, ret);
  465.     }

  466.     /**
  467.      * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
  468.      *
  469.      * @param n Utf8 string to add
  470.      * @return index of entry
  471.      */
  472.     public int addUtf8(final String n) {
  473.         int ret;
  474.         if ((ret = lookupUtf8(n)) != -1) {
  475.             return ret; // Already in CP
  476.         }
  477.         adjustSize();
  478.         ret = index;
  479.         constants[index++] = new ConstantUtf8(n);
  480.         return computeIfAbsent(utf8Table, n, ret);
  481.     }

  482.     /**
  483.      * Resize internal array of constants.
  484.      */
  485.     protected void adjustSize() {
  486.         // 3 extra spaces are needed as some entries may take 3 slots
  487.         if (index + 3 >= Const.MAX_CP_ENTRIES + 1) {
  488.             throw new IllegalStateException("The number of constants " + (index + 3)
  489.                     + " is over the size of the constant pool: "
  490.                     + Const.MAX_CP_ENTRIES);
  491.         }

  492.         if (index + 3 >= size) {
  493.             final Constant[] tmp = constants;
  494.             size *= 2;
  495.             // the constant array shall not exceed the size of the constant pool
  496.             size = Math.min(size, Const.MAX_CP_ENTRIES + 1);
  497.             constants = new Constant[size];
  498.             System.arraycopy(tmp, 0, constants, 0, index);
  499.         }
  500.     }

  501.     private int computeIfAbsent(final Map<String, Integer> map, final String key, final int value) {
  502.         return map.computeIfAbsent(key, k -> Integer.valueOf(value));
  503.     }

  504.     /**
  505.      * @param i index in constant pool
  506.      * @return constant pool entry at index i
  507.      */
  508.     public Constant getConstant(final int i) {
  509.         return constants[i];
  510.     }

  511.     /**
  512.      * @return intermediate constant pool
  513.      */
  514.     public ConstantPool getConstantPool() {
  515.         return new ConstantPool(constants);
  516.     }

  517.     /**
  518.      * @return constant pool with proper length
  519.      */
  520.     public ConstantPool getFinalConstantPool() {
  521.         return new ConstantPool(Arrays.copyOf(constants, index));
  522.     }

  523.     private int getIndex(final Map<String, Integer> map, final String key) {
  524.         return toIndex(map.get(key));
  525.     }

  526.     /**
  527.      * @return current size of constant pool
  528.      */
  529.     public int getSize() {
  530.         return index;
  531.     }

  532.     /**
  533.      * Look for ConstantClass in ConstantPool named 'str'.
  534.      *
  535.      * @param str String to search for
  536.      * @return index on success, -1 otherwise
  537.      */
  538.     public int lookupClass(final String str) {
  539.         return getIndex(classTable, Utility.packageToPath(str));
  540.     }

  541.     /**
  542.      * Look for ConstantDouble in ConstantPool.
  543.      *
  544.      * @param n Double number to look for
  545.      * @return index on success, -1 otherwise
  546.      */
  547.     public int lookupDouble(final double n) {
  548.         final long bits = Double.doubleToLongBits(n);
  549.         for (int i = 1; i < index; i++) {
  550.             if (constants[i] instanceof ConstantDouble) {
  551.                 final ConstantDouble c = (ConstantDouble) constants[i];
  552.                 if (Double.doubleToLongBits(c.getBytes()) == bits) {
  553.                     return i;
  554.                 }
  555.             }
  556.         }
  557.         return -1;
  558.     }

  559.     /**
  560.      * Look for ConstantFieldref in ConstantPool.
  561.      *
  562.      * @param className Where to find method
  563.      * @param fieldName Guess what
  564.      * @param signature return and argument types
  565.      * @return index on success, -1 otherwise
  566.      */
  567.     public int lookupFieldref(final String className, final String fieldName, final String signature) {
  568.         return getIndex(cpTable, className + FIELDREF_DELIM + fieldName + FIELDREF_DELIM + signature);
  569.     }

  570.     /**
  571.      * Look for ConstantFloat in ConstantPool.
  572.      *
  573.      * @param n Float number to look for
  574.      * @return index on success, -1 otherwise
  575.      */
  576.     public int lookupFloat(final float n) {
  577.         final int bits = Float.floatToIntBits(n);
  578.         for (int i = 1; i < index; i++) {
  579.             if (constants[i] instanceof ConstantFloat) {
  580.                 final ConstantFloat c = (ConstantFloat) constants[i];
  581.                 if (Float.floatToIntBits(c.getBytes()) == bits) {
  582.                     return i;
  583.                 }
  584.             }
  585.         }
  586.         return -1;
  587.     }

  588.     /**
  589.      * Look for ConstantInteger in ConstantPool.
  590.      *
  591.      * @param n integer number to look for
  592.      * @return index on success, -1 otherwise
  593.      */
  594.     public int lookupInteger(final int n) {
  595.         for (int i = 1; i < index; i++) {
  596.             if (constants[i] instanceof ConstantInteger) {
  597.                 final ConstantInteger c = (ConstantInteger) constants[i];
  598.                 if (c.getBytes() == n) {
  599.                     return i;
  600.                 }
  601.             }
  602.         }
  603.         return -1;
  604.     }

  605.     public int lookupInterfaceMethodref(final MethodGen method) {
  606.         return lookupInterfaceMethodref(method.getClassName(), method.getName(), method.getSignature());
  607.     }

  608.     /**
  609.      * Look for ConstantInterfaceMethodref in ConstantPool.
  610.      *
  611.      * @param className Where to find method
  612.      * @param methodName Guess what
  613.      * @param signature return and argument types
  614.      * @return index on success, -1 otherwise
  615.      */
  616.     public int lookupInterfaceMethodref(final String className, final String methodName, final String signature) {
  617.         return getIndex(cpTable, className + IMETHODREF_DELIM + methodName + IMETHODREF_DELIM + signature);
  618.     }

  619.     /**
  620.      * Look for ConstantLong in ConstantPool.
  621.      *
  622.      * @param n Long number to look for
  623.      * @return index on success, -1 otherwise
  624.      */
  625.     public int lookupLong(final long n) {
  626.         for (int i = 1; i < index; i++) {
  627.             if (constants[i] instanceof ConstantLong) {
  628.                 final ConstantLong c = (ConstantLong) constants[i];
  629.                 if (c.getBytes() == n) {
  630.                     return i;
  631.                 }
  632.             }
  633.         }
  634.         return -1;
  635.     }

  636.     public int lookupMethodref(final MethodGen method) {
  637.         return lookupMethodref(method.getClassName(), method.getName(), method.getSignature());
  638.     }

  639.     /**
  640.      * Look for ConstantMethodref in ConstantPool.
  641.      *
  642.      * @param className Where to find method
  643.      * @param methodName Guess what
  644.      * @param signature return and argument types
  645.      * @return index on success, -1 otherwise
  646.      */
  647.     public int lookupMethodref(final String className, final String methodName, final String signature) {
  648.         return getIndex(cpTable, className + METHODREF_DELIM + methodName + METHODREF_DELIM + signature);
  649.     }

  650.     /**
  651.      * Look for ConstantNameAndType in ConstantPool.
  652.      *
  653.      * @param name of variable/method
  654.      * @param signature of variable/method
  655.      * @return index on success, -1 otherwise
  656.      */
  657.     public int lookupNameAndType(final String name, final String signature) {
  658.         return getIndex(natTable, name + NAT_DELIM + signature);
  659.     }

  660.     /**
  661.      * Look for ConstantString in ConstantPool containing String 'str'.
  662.      *
  663.      * @param str String to search for
  664.      * @return index on success, -1 otherwise
  665.      */
  666.     public int lookupString(final String str) {
  667.         return getIndex(stringTable, str);
  668.     }

  669.     /**
  670.      * Look for ConstantUtf8 in ConstantPool.
  671.      *
  672.      * @param n Utf8 string to look for
  673.      * @return index on success, -1 otherwise
  674.      */
  675.     public int lookupUtf8(final String n) {
  676.         return getIndex(utf8Table, n);
  677.     }

  678.     /**
  679.      * Use with care!
  680.      *
  681.      * @param i index in constant pool
  682.      * @param c new constant pool entry at index i
  683.      */
  684.     public void setConstant(final int i, final Constant c) {
  685.         constants[i] = c;
  686.     }

  687.     private int toIndex(final Integer index) {
  688.         return index != null ? index.intValue() : -1;
  689.     }

  690.     /**
  691.      * @return String representation.
  692.      */
  693.     @Override
  694.     public String toString() {
  695.         final StringBuilder buf = new StringBuilder();
  696.         for (int i = 1; i < index; i++) {
  697.             buf.append(i).append(")").append(constants[i]).append("\n");
  698.         }
  699.         return buf.toString();
  700.     }
  701. }