You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by jg...@apache.org on 2022/07/22 12:46:47 UTC

[tomee] 01/01: Patch to ensure the ConstantPool is not exceeded

This is an automated email from the ASF dual-hosted git repository.

jgallimore pushed a commit to branch TOMEE-4015
in repository https://gitbox.apache.org/repos/asf/tomee.git

commit a17071bb66033e502d9347a70d242b00e5dd0a18
Author: Jonathan Gallimore <jo...@jrg.me.uk>
AuthorDate: Fri Jul 22 13:45:45 2022 +0100

    Patch to ensure the ConstantPool is not exceeded
---
 deps/taglibs-shade/pom.xml                         |  18 +
 .../org/apache/bcel/classfile/ConstantPool.java    | 378 ++++++++++
 .../org/apache/bcel/generic/ConstantPoolGen.java   | 794 +++++++++++++++++++++
 3 files changed, 1190 insertions(+)

diff --git a/deps/taglibs-shade/pom.xml b/deps/taglibs-shade/pom.xml
index 12ffb0712d..3e435e5ae3 100644
--- a/deps/taglibs-shade/pom.xml
+++ b/deps/taglibs-shade/pom.xml
@@ -143,6 +143,24 @@
           </execution>
         </executions>
       </plugin>
+      <plugin>
+        <groupId>org.apache.tomee.patch</groupId>
+        <artifactId>tomee-patch-plugin</artifactId>
+        <configuration>
+          <select>taglibs-shade-.*\.jar</select>
+          <transformSources>false</transformSources>
+          <source>1.8</source>
+          <target>1.8</target>
+        </configuration>
+        <executions>
+          <execution>
+            <goals>
+              <goal>run</goal>
+            </goals>
+            <phase>package</phase>
+          </execution>
+        </executions>
+      </plugin>
     </plugins>
   </build>
 </project>
diff --git a/deps/taglibs-shade/src/patch/java/openejb/shade/org/apache/bcel/classfile/ConstantPool.java b/deps/taglibs-shade/src/patch/java/openejb/shade/org/apache/bcel/classfile/ConstantPool.java
new file mode 100644
index 0000000000..a1268d21b5
--- /dev/null
+++ b/deps/taglibs-shade/src/patch/java/openejb/shade/org/apache/bcel/classfile/ConstantPool.java
@@ -0,0 +1,378 @@
+package openejb.shade.org.apache.bcel.classfile;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache BCEL" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache BCEL", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import  openejb.shade.org.apache.bcel.Constants;
+import  openejb.shade.org.apache.bcel.generic.ConstantPoolGen;
+import  java.io.*;
+
+/**
+ * This class represents the constant pool, i.e., a table of constants.
+ * It may contain null references, due to the JVM specification that skips
+ * an entry after an 8-byte constant (double, long) entry.
+ *
+ * @version $Id$
+ * @see     Constant
+ * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
+ */
+public class ConstantPool implements Cloneable, Node {
+    private int        constant_pool_count;
+    private Constant[] constant_pool;
+
+    /**
+     * @param constant_pool Array of constants
+     */
+    public ConstantPool(Constant[] constant_pool)
+    {
+        setConstantPool(constant_pool);
+    }
+
+    /**
+     * Read constants from given file stream.
+     *
+     * @param file Input stream
+     * @throw IOException
+     * @throw ClassFormatError
+     */
+    ConstantPool(DataInputStream file) throws IOException, ClassFormatError
+    {
+        byte tag;
+
+        constant_pool_count = file.readUnsignedShort();
+        constant_pool       = new Constant[constant_pool_count];
+
+        /* constant_pool[0] is unused by the compiler and may be used freely
+         * by the implementation.
+         */
+        for(int i=1; i < constant_pool_count; i++) {
+            constant_pool[i] = Constant.readConstant(file);
+
+            /* Quote from the JVM specification:
+             * "All eight byte constants take up two spots in the constant pool.
+             * If this is the n'th byte in the constant pool, then the next item
+             * will be numbered n+2"
+             *
+             * Thus we have to increment the index counter.
+             */
+            tag = constant_pool[i].getTag();
+            if((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long))
+                i++;
+        }
+    }
+
+    /**
+     * Called by objects that are traversing the nodes of the tree implicitely
+     * defined by the contents of a Java class. I.e., the hierarchy of methods,
+     * fields, attributes, etc. spawns a tree of objects.
+     *
+     * @param v Visitor object
+     */
+    public void accept(Visitor v) {
+        v.visitConstantPool(this);
+    }
+
+    /**
+     * Resolve constant to a string representation.
+     *
+     * @param  constant Constant to be printed
+     * @return String representation
+     */
+    public String constantToString(Constant c)
+            throws ClassFormatError
+    {
+        String   str;
+        int      i;
+        byte     tag = c.getTag();
+
+        switch(tag) {
+            case Constants.CONSTANT_Class:
+                i   = ((ConstantClass)c).getNameIndex();
+                c   = getConstant(i, Constants.CONSTANT_Utf8);
+                str = Utility.compactClassName(((ConstantUtf8)c).getBytes(), false);
+                break;
+
+            case Constants.CONSTANT_String:
+                i   = ((ConstantString)c).getStringIndex();
+                c   = getConstant(i, Constants.CONSTANT_Utf8);
+                str = "\"" + escape(((ConstantUtf8)c).getBytes()) + "\"";
+                break;
+
+            case Constants.CONSTANT_Utf8:    str = ((ConstantUtf8)c).getBytes();         break;
+            case Constants.CONSTANT_Double:  str = "" + ((ConstantDouble)c).getBytes();  break;
+            case Constants.CONSTANT_Float:   str = "" + ((ConstantFloat)c).getBytes();   break;
+            case Constants.CONSTANT_Long:    str = "" + ((ConstantLong)c).getBytes();    break;
+            case Constants.CONSTANT_Integer: str = "" + ((ConstantInteger)c).getBytes(); break;
+
+            case Constants.CONSTANT_NameAndType:
+                str = (constantToString(((ConstantNameAndType)c).getNameIndex(),
+                        Constants.CONSTANT_Utf8) + " " +
+                        constantToString(((ConstantNameAndType)c).getSignatureIndex(),
+                                Constants.CONSTANT_Utf8));
+                break;
+
+            case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref:
+            case Constants.CONSTANT_Fieldref:
+                str = (constantToString(((ConstantCP)c).getClassIndex(),
+                        Constants.CONSTANT_Class) + "." +
+                        constantToString(((ConstantCP)c).getNameAndTypeIndex(),
+                                Constants.CONSTANT_NameAndType));
+                break;
+
+            default: // Never reached
+                throw new RuntimeException("Unknown constant type " + tag);
+        }
+
+        return str;
+    }
+
+    private static final String escape(String str) {
+        int          len = str.length();
+        StringBuffer buf = new StringBuffer(len + 5);
+        char[]       ch  = str.toCharArray();
+
+        for(int i=0; i < len; i++) {
+            switch(ch[i]) {
+                case '\n' : buf.append("\\n"); break;
+                case '\r' : buf.append("\\r"); break;
+                case '\t' : buf.append("\\t"); break;
+                case '\b' : buf.append("\\b"); break;
+                case '"'  : buf.append("\\\""); break;
+                default: buf.append(ch[i]);
+            }
+        }
+
+        return buf.toString();
+    }
+
+
+    /**
+     * Retrieve constant at `index' from constant pool and resolve it to
+     * a string representation.
+     *
+     * @param  index of constant in constant pool
+     * @param  tag expected type
+     * @return String representation
+     */
+    public String constantToString(int index, byte tag)
+            throws ClassFormatError
+    {
+        Constant c = getConstant(index, tag);
+        return constantToString(c);
+    }
+
+    /**
+     * Dump constant pool to file stream in binary format.
+     *
+     * @param file Output file stream
+     * @throw IOException
+     */
+    public void dump(DataOutputStream file) throws IOException
+    {
+        /*
+         * Constants over the size of the constant pool shall not be written out.
+         * This is a redundant measure as the ConstantPoolGen should have already
+         * reported an error back in the situation.
+         */
+        int size = constant_pool_count < ConstantPoolGen.CONSTANT_POOL_SIZE - 1 ?
+                   constant_pool_count : ConstantPoolGen.CONSTANT_POOL_SIZE - 1;
+
+        file.writeShort(size);
+
+        for(int i=1; i < size; i++)
+            if(constant_pool[i] != null)
+                constant_pool[i].dump(file);
+    }
+
+    /**
+     * Get constant from constant pool.
+     *
+     * @param  index Index in constant pool
+     * @return Constant value
+     * @see    Constant
+     */
+    public Constant getConstant(int index) {
+        if (index >= constant_pool.length || index < 0)
+            throw new ClassFormatError("Invalid constant pool reference: " +
+                    index + ". Constant pool size is: " +
+                    constant_pool.length);
+        return constant_pool[index];
+    }
+
+    /**
+     * Get constant from constant pool and check whether it has the
+     * expected type.
+     *
+     * @param  index Index in constant pool
+     * @param  tag Tag of expected constant, i.e., its type
+     * @return Constant value
+     * @see    Constant
+     * @throw  ClassFormatError
+     */
+    public Constant getConstant(int index, byte tag)
+            throws ClassFormatError
+    {
+        Constant c;
+
+        c = getConstant(index);
+
+        if(c == null)
+            throw new ClassFormatError("Constant pool at index " + index + " is null.");
+
+        if(c.getTag() == tag)
+            return c;
+        else
+            throw new ClassFormatError("Expected class `" + Constants.CONSTANT_NAMES[tag] +
+                    "' at index " + index + " and got " + c);
+    }
+
+    /**
+     * @return Array of constants.
+     * @see    Constant
+     */
+    public Constant[] getConstantPool() { return constant_pool;  }
+    /**
+     * Get string from constant pool and bypass the indirection of
+     * `ConstantClass' and `ConstantString' objects. I.e. these classes have
+     * an index field that points to another entry of the constant pool of
+     * type `ConstantUtf8' which contains the real data.
+     *
+     * @param  index Index in constant pool
+     * @param  tag Tag of expected constant, either ConstantClass or ConstantString
+     * @return Contents of string reference
+     * @see    ConstantClass
+     * @see    ConstantString
+     * @throw  ClassFormatError
+     */
+    public String getConstantString(int index, byte tag)
+            throws ClassFormatError
+    {
+        Constant c;
+        int    i;
+        String   s;
+
+        c = getConstant(index, tag);
+
+        /* This switch() is not that elegant, since the two classes have the
+         * same contents, they just differ in the name of the index
+         * field variable.
+         * But we want to stick to the JVM naming conventions closely though
+         * we could have solved these more elegantly by using the same
+         * variable name or by subclassing.
+         */
+        switch(tag) {
+            case Constants.CONSTANT_Class:  i = ((ConstantClass)c).getNameIndex();    break;
+            case Constants.CONSTANT_String: i = ((ConstantString)c).getStringIndex(); break;
+            default:
+                throw new RuntimeException("getConstantString called with illegal tag " + tag);
+        }
+
+        // Finally get the string from the constant pool
+        c = getConstant(i, Constants.CONSTANT_Utf8);
+        return ((ConstantUtf8)c).getBytes();
+    }
+    /**
+     * @return Length of constant pool.
+     */
+    public int getLength()
+    {
+        return constant_pool_count;
+    }
+
+    /**
+     * @param constant Constant to set
+     */
+    public void setConstant(int index, Constant constant) {
+        constant_pool[index] = constant;
+    }
+
+    /**
+     * @param constant_pool
+     */
+    public void setConstantPool(Constant[] constant_pool) {
+        this.constant_pool = constant_pool;
+        constant_pool_count = (constant_pool == null)? 0 : constant_pool.length;
+    }
+    /**
+     * @return String representation.
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+
+        for(int i=1; i < constant_pool_count; i++)
+            buf.append(i + ")" + constant_pool[i] + "\n");
+
+        return buf.toString();
+    }
+
+    /**
+     * @return deep copy of this constant pool
+     */
+    public ConstantPool copy() {
+        ConstantPool c = null;
+
+        try {
+            c = (ConstantPool)clone();
+        } catch(CloneNotSupportedException e) {}
+
+        c.constant_pool = new Constant[constant_pool_count];
+
+        for(int i=1; i < constant_pool_count; i++) {
+            if(constant_pool[i] != null)
+                c.constant_pool[i] = constant_pool[i].copy();
+        }
+
+        return c;
+    }
+}
diff --git a/deps/taglibs-shade/src/patch/java/openejb/shade/org/apache/bcel/generic/ConstantPoolGen.java b/deps/taglibs-shade/src/patch/java/openejb/shade/org/apache/bcel/generic/ConstantPoolGen.java
new file mode 100644
index 0000000000..b836a124df
--- /dev/null
+++ b/deps/taglibs-shade/src/patch/java/openejb/shade/org/apache/bcel/generic/ConstantPoolGen.java
@@ -0,0 +1,794 @@
+package org.apache.bcel.generic;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation.  All rights
+ * reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ *    if any, must include the following acknowledgment:
+ *       "This product includes software developed by the
+ *        Apache Software Foundation (http://www.apache.org/)."
+ *    Alternately, this acknowledgment may appear in the software itself,
+ *    if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ *    "Apache BCEL" must not be used to endorse or promote products
+ *    derived from this software without prior written permission. For
+ *    written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ *    "Apache BCEL", nor may "Apache" appear in their name, without
+ *    prior written permission of the Apache Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.bcel.Constants;
+import org.apache.bcel.classfile.*;
+import java.util.HashMap;
+
+/**
+ * This class is used to build up a constant pool. The user adds
+ * constants via `addXXX' methods, `addString', `addClass',
+ * etc.. These methods return an index into the constant
+ * pool. Finally, `getFinalConstantPool()' returns the constant pool
+ * built up. Intermediate versions of the constant pool can be
+ * obtained with `getConstantPool()'. A constant pool has capacity for
+ * Constants.MAX_SHORT entries. Note that the first (0) is used by the
+ * JVM and that Double and Long constants need two slots.
+ *
+ * @version $Id$
+ * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
+ * @see Constant
+ */
+public class ConstantPoolGen {
+    public static final int CONSTANT_POOL_SIZE = 65536;
+    private static final int DEFAULT_BUFFER_SIZE = 256;
+    protected int        size      = 1024; // Inital size, sufficient in most cases
+    protected Constant[] constants = new Constant[size];
+    protected int        index     = 1; // First entry (0) used by JVM
+
+    private static final String METHODREF_DELIM  = ":";
+    private static final String IMETHODREF_DELIM = "#";
+    private static final String FIELDREF_DELIM   = "&";
+    private static final String NAT_DELIM        = "%";
+
+    private static class Index {
+        int index;
+        Index(int i) { index = i; }
+    }
+
+    /**
+     * Initialize with given array of constants.
+     *
+     * @param c array of given constants, new ones will be appended
+     */
+    public ConstantPoolGen(Constant[] cs) {
+        size = Math.min(Math.max(DEFAULT_BUFFER_SIZE, cs.length + 64), CONSTANT_POOL_SIZE);
+        constants = new Constant[size];
+
+        System.arraycopy(cs, 0, constants, 0, cs.length);
+
+        if(cs.length > 0)
+            index = cs.length;
+
+        for(int i=1; i < index; i++) {
+            Constant c = constants[i];
+
+            if(c instanceof ConstantString) {
+                ConstantString s  = (ConstantString)c;
+                ConstantUtf8   u8 = (ConstantUtf8)constants[s.getStringIndex()];
+
+                string_table.put(u8.getBytes(), new Index(i));
+            } else if(c instanceof ConstantClass) {
+                ConstantClass s  = (ConstantClass)c;
+                ConstantUtf8  u8 = (ConstantUtf8)constants[s.getNameIndex()];
+
+                class_table.put(u8.getBytes(), new Index(i));
+            } else if(c instanceof ConstantNameAndType) {
+                ConstantNameAndType n    = (ConstantNameAndType)c;
+                ConstantUtf8        u8   = (ConstantUtf8)constants[n.getNameIndex()];
+                ConstantUtf8        u8_2 = (ConstantUtf8)constants[n.getSignatureIndex()];
+
+                n_a_t_table.put(u8.getBytes() + NAT_DELIM + u8_2.getBytes(), new Index(i));
+            } else if(c instanceof ConstantUtf8) {
+                ConstantUtf8 u = (ConstantUtf8)c;
+
+                utf8_table.put(u.getBytes(), new Index(i));
+            } else if(c instanceof ConstantCP) {
+                ConstantCP          m     = (ConstantCP)c;
+                ConstantClass       clazz = (ConstantClass)constants[m.getClassIndex()];
+                ConstantNameAndType n     = (ConstantNameAndType)constants[m.getNameAndTypeIndex()];
+
+                ConstantUtf8 u8         = (ConstantUtf8)constants[clazz.getNameIndex()];
+                String       class_name = u8.getBytes().replace('/', '.');
+
+                u8 = (ConstantUtf8)constants[n.getNameIndex()];
+                String method_name = u8.getBytes();
+
+                u8 = (ConstantUtf8)constants[n.getSignatureIndex()];
+                String signature = u8.getBytes();
+
+                String delim = METHODREF_DELIM;
+
+                if(c instanceof ConstantInterfaceMethodref)
+                    delim = IMETHODREF_DELIM;
+                else if(c instanceof ConstantFieldref)
+                    delim = FIELDREF_DELIM;
+
+                cp_table.put(class_name + delim + method_name + delim + signature, new Index(i));
+            }
+        }
+    }
+
+    /**
+     * Initialize with given constant pool.
+     */
+    public ConstantPoolGen(ConstantPool cp) {
+        this(cp.getConstantPool());
+    }
+
+    /**
+     * Create empty constant pool.
+     */
+    public ConstantPoolGen() {}
+
+    /** Resize internal array of constants.
+     */
+    protected void adjustSize() {
+        // 3 extra spaces are needed as some entries may take 3 slots
+        if (index + 3 >= CONSTANT_POOL_SIZE) {
+            throw new RuntimeException("The number of constants " + (index + 3)
+                    + " is over the size of the constant pool: "
+                    + (CONSTANT_POOL_SIZE - 1));
+        }
+
+
+        if(index + 3 >= size) {
+            Constant[] cs = constants;
+
+            size      *= 2;
+
+            // the constant array shall not exceed the size of the constant pool
+            size = Math.min(size, CONSTANT_POOL_SIZE);
+
+            constants  = new Constant[size];
+            System.arraycopy(cs, 0, constants, 0, index);
+        }
+    }
+
+    private HashMap string_table = new HashMap();
+
+    /**
+     * Look for ConstantString in ConstantPool containing String `str'.
+     *
+     * @param str String to search for
+     * @return index on success, -1 otherwise
+     */
+    public int lookupString(String str) {
+        Index index = (Index)string_table.get(str);
+        return (index != null)? index.index : -1;
+    }
+
+    /**
+     * Add a new String constant to the ConstantPool, if it is not already in there.
+     *
+     * @param str String to add
+     * @return index of entry
+     */
+    public int addString(String str) {
+        int ret;
+
+        if((ret = lookupString(str)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        ConstantUtf8   u8 = new ConstantUtf8(str);
+        ConstantString s  = new ConstantString(index);
+
+        constants[index++] = u8;
+        ret = index;
+        constants[index++] = s;
+
+        string_table.put(str, new Index(ret));
+
+        return ret;
+    }
+
+    private HashMap class_table = new HashMap();
+
+    /**
+     * Look for ConstantClass in ConstantPool named `str'.
+     *
+     * @param str String to search for
+     * @return index on success, -1 otherwise
+     */
+    public int lookupClass(String str) {
+        Index index = (Index)class_table.get(str.replace('.', '/'));
+        return (index != null)? index.index : -1;
+    }
+
+    private int addClass_(String clazz) {
+        int    ret;
+
+        if((ret = lookupClass(clazz)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        ConstantClass c = new ConstantClass(addUtf8(clazz));
+
+        ret = index;
+        constants[index++] = c;
+
+        class_table.put(clazz, new Index(ret));
+
+        return ret;
+    }
+
+    /**
+     * Add a new Class reference to the ConstantPool, if it is not already in there.
+     *
+     * @param str Class to add
+     * @return index of entry
+     */
+    public int addClass(String str) {
+        return addClass_(str.replace('.', '/'));
+    }
+
+    /**
+     * Add a new Class reference to the ConstantPool for a given type.
+     *
+     * @param str Class to add
+     * @return index of entry
+     */
+    public int addClass(ObjectType type) {
+        return addClass(type.getClassName());
+    }
+
+    /**
+     * Add a reference to an array class (e.g. String[][]) as needed by MULTIANEWARRAY
+     * instruction, e.g. to the ConstantPool.
+     *
+     * @param type type of array class
+     * @return index of entry
+     */
+    public int addArrayClass(ArrayType type) {
+        return addClass_(type.getSignature());
+    }
+
+    /**
+     * Look for ConstantInteger in ConstantPool.
+     *
+     * @param n integer number to look for
+     * @return index on success, -1 otherwise
+     */
+    public int lookupInteger(int n) {
+        for(int i=1; i < index; i++) {
+            if(constants[i] instanceof ConstantInteger) {
+                ConstantInteger c = (ConstantInteger)constants[i];
+
+                if(c.getBytes() == n)
+                    return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Add a new Integer constant to the ConstantPool, if it is not already in there.
+     *
+     * @param n integer number to add
+     * @return index of entry
+     */
+    public int addInteger(int n) {
+        int  ret;
+
+        if((ret = lookupInteger(n)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        ret = index;
+        constants[index++] = new ConstantInteger(n);
+
+        return ret;
+    }
+
+    /**
+     * Look for ConstantFloat in ConstantPool.
+     *
+     * @param n Float number to look for
+     * @return index on success, -1 otherwise
+     */
+    public int lookupFloat(float n) {
+        for(int i=1; i < index; i++) {
+            if(constants[i] instanceof ConstantFloat) {
+                ConstantFloat c = (ConstantFloat)constants[i];
+
+                if(c.getBytes() == n)
+                    return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Add a new Float constant to the ConstantPool, if it is not already in there.
+     *
+     * @param n Float number to add
+     * @return index of entry
+     */
+    public int addFloat(float n) {
+        int  ret;
+
+        if((ret = lookupFloat(n)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        ret = index;
+        constants[index++] = new ConstantFloat(n);
+
+        return ret;
+    }
+
+    private HashMap utf8_table = new HashMap();
+
+    /**
+     * Look for ConstantUtf8 in ConstantPool.
+     *
+     * @param n Utf8 string to look for
+     * @return index on success, -1 otherwise
+     */
+    public int lookupUtf8(String n) {
+        Index index = (Index)utf8_table.get(n);
+
+        return (index != null)? index.index : -1;
+    }
+
+    /**
+     * Add a new Utf8 constant to the ConstantPool, if it is not already in there.
+     *
+     * @param n Utf8 string to add
+     * @return index of entry
+     */
+    public int addUtf8(String n) {
+        int  ret;
+
+        if((ret = lookupUtf8(n)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        ret = index;
+        constants[index++] = new ConstantUtf8(n);
+
+        utf8_table.put(n, new Index(ret));
+
+        return ret;
+    }
+
+    /**
+     * Look for ConstantLong in ConstantPool.
+     *
+     * @param n Long number to look for
+     * @return index on success, -1 otherwise
+     */
+    public int lookupLong(long n) {
+        for(int i=1; i < index; i++) {
+            if(constants[i] instanceof ConstantLong) {
+                ConstantLong c = (ConstantLong)constants[i];
+
+                if(c.getBytes() == n)
+                    return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Add a new long constant to the ConstantPool, if it is not already in there.
+     *
+     * @param n Long number to add
+     * @return index of entry
+     */
+    public int addLong(long n) {
+        int  ret;
+
+        if((ret = lookupLong(n)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        ret = index;
+        constants[index] = new ConstantLong(n);
+        index += 2;   // Wastes one entry according to spec
+
+        return ret;
+    }
+
+    /**
+     * Look for ConstantDouble in ConstantPool.
+     *
+     * @param n Double number to look for
+     * @return index on success, -1 otherwise
+     */
+    public int lookupDouble(double n) {
+        for(int i=1; i < index; i++) {
+            if(constants[i] instanceof ConstantDouble) {
+                ConstantDouble c = (ConstantDouble)constants[i];
+
+                if(c.getBytes() == n)
+                    return i;
+            }
+        }
+
+        return -1;
+    }
+
+    /**
+     * Add a new double constant to the ConstantPool, if it is not already in there.
+     *
+     * @param n Double number to add
+     * @return index of entry
+     */
+    public int addDouble(double n) {
+        int  ret;
+
+        if((ret = lookupDouble(n)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        ret = index;
+        constants[index] = new ConstantDouble(n);
+        index += 2;   // Wastes one entry according to spec
+
+        return ret;
+    }
+
+    private HashMap n_a_t_table = new HashMap();
+
+    /**
+     * Look for ConstantNameAndType in ConstantPool.
+     *
+     * @param name of variable/method
+     * @param signature of variable/method
+     * @return index on success, -1 otherwise
+     */
+    public int lookupNameAndType(String name, String signature) {
+        Index index = (Index)n_a_t_table.get(name + NAT_DELIM + signature);
+        return (index != null)? index.index : -1;
+    }
+
+    /**
+     * Add a new NameAndType constant to the ConstantPool if it is not already
+     * in there.
+     *
+     * @param n NameAndType string to add
+     * @return index of entry
+     */
+    public int addNameAndType(String name, String signature) {
+        int  ret;
+        int  name_index, signature_index;
+
+        if((ret = lookupNameAndType(name, signature)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        name_index      = addUtf8(name);
+        signature_index = addUtf8(signature);
+        ret = index;
+        constants[index++] = new ConstantNameAndType(name_index, signature_index);
+
+        n_a_t_table.put(name + NAT_DELIM + signature, new Index(ret));
+        return ret;
+    }
+
+    private HashMap cp_table = new HashMap();
+
+    /**
+     * Look for ConstantMethodref in ConstantPool.
+     *
+     * @param class_name Where to find method
+     * @param method_name Guess what
+     * @param signature return and argument types
+     * @return index on success, -1 otherwise
+     */
+    public int lookupMethodref(String class_name, String method_name, String signature) {
+        Index index = (Index)cp_table.get(class_name + METHODREF_DELIM + method_name +
+                METHODREF_DELIM + signature);
+        return (index != null)? index.index : -1;
+    }
+
+    public int lookupMethodref(MethodGen method) {
+        return lookupMethodref(method.getClassName(), method.getName(),
+                method.getSignature());
+    }
+
+    /**
+     * Add a new Methodref constant to the ConstantPool, if it is not already
+     * in there.
+     *
+     * @param n Methodref string to add
+     * @return index of entry
+     */
+    public int addMethodref(String class_name, String method_name, String signature) {
+        int  ret, class_index, name_and_type_index;
+
+        if((ret = lookupMethodref(class_name, method_name, signature)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        name_and_type_index = addNameAndType(method_name, signature);
+        class_index         = addClass(class_name);
+        ret = index;
+        constants[index++] = new ConstantMethodref(class_index, name_and_type_index);
+
+        cp_table.put(class_name + METHODREF_DELIM + method_name +
+                METHODREF_DELIM + signature, new Index(ret));
+
+        return ret;
+    }
+
+    public int addMethodref(MethodGen method) {
+        return addMethodref(method.getClassName(), method.getName(),
+                method.getSignature());
+    }
+
+    /**
+     * Look for ConstantInterfaceMethodref in ConstantPool.
+     *
+     * @param class_name Where to find method
+     * @param method_name Guess what
+     * @param signature return and argument types
+     * @return index on success, -1 otherwise
+     */
+    public int lookupInterfaceMethodref(String class_name, String method_name, String signature) {
+        Index index = (Index)cp_table.get(class_name + IMETHODREF_DELIM + method_name +
+                IMETHODREF_DELIM + signature);
+        return (index != null)? index.index : -1;
+    }
+
+    public int lookupInterfaceMethodref(MethodGen method) {
+        return lookupInterfaceMethodref(method.getClassName(), method.getName(),
+                method.getSignature());
+    }
+
+    /**
+     * Add a new InterfaceMethodref constant to the ConstantPool, if it is not already
+     * in there.
+     *
+     * @param n InterfaceMethodref string to add
+     * @return index of entry
+     */
+    public int addInterfaceMethodref(String class_name, String method_name, String signature) {
+        int ret, class_index, name_and_type_index;
+
+        if((ret = lookupInterfaceMethodref(class_name, method_name, signature)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        class_index         = addClass(class_name);
+        name_and_type_index = addNameAndType(method_name, signature);
+        ret = index;
+        constants[index++] = new ConstantInterfaceMethodref(class_index, name_and_type_index);
+
+        cp_table.put(class_name + IMETHODREF_DELIM + method_name +
+                IMETHODREF_DELIM + signature, new Index(ret));
+
+        return ret;
+    }
+
+    public int addInterfaceMethodref(MethodGen method) {
+        return addInterfaceMethodref(method.getClassName(), method.getName(),
+                method.getSignature());
+    }
+
+    /**
+     * Look for ConstantFieldref in ConstantPool.
+     *
+     * @param class_name Where to find method
+     * @param field_name Guess what
+     * @param signature return and argument types
+     * @return index on success, -1 otherwise
+     */
+    public int lookupFieldref(String class_name, String field_name, String signature) {
+        Index index = (Index)cp_table.get(class_name + FIELDREF_DELIM + field_name +
+                FIELDREF_DELIM + signature);
+        return (index != null)? index.index : -1;
+    }
+
+    /**
+     * Add a new Fieldref constant to the ConstantPool, if it is not already
+     * in there.
+     *
+     * @param n Fieldref string to add
+     * @return index of entry
+     */
+    public int addFieldref(String class_name, String field_name, String signature) {
+        int  ret;
+        int  class_index, name_and_type_index;
+
+        if((ret = lookupFieldref(class_name, field_name, signature)) != -1)
+            return ret; // Already in CP
+
+        adjustSize();
+
+        class_index         = addClass(class_name);
+        name_and_type_index = addNameAndType(field_name, signature);
+        ret = index;
+        constants[index++] = new ConstantFieldref(class_index, name_and_type_index);
+
+        cp_table.put(class_name + FIELDREF_DELIM + field_name + FIELDREF_DELIM + signature, new Index(ret));
+
+        return ret;
+    }
+
+    /**
+     * @param i index in constant pool
+     * @return constant pool entry at index i
+     */
+    public Constant getConstant(int i) { return constants[i]; }
+
+    /**
+     * Use with care!
+     *
+     * @param i index in constant pool
+     * @param c new constant pool entry at index i
+     */
+    public void setConstant(int i, Constant c) { constants[i] = c; }
+
+    /**
+     * @return intermediate constant pool
+     */
+    public ConstantPool getConstantPool() {
+        return new ConstantPool(constants);
+    }
+
+    /**
+     * @return current size of constant pool
+     */
+    public int getSize() {
+        return index;
+    }
+
+    /**
+     * @return constant pool with proper length
+     */
+    public ConstantPool getFinalConstantPool() {
+        Constant[] cs = new Constant[index];
+
+        System.arraycopy(constants, 0, cs, 0, index);
+
+        return new ConstantPool(cs);
+    }
+
+    /**
+     * @return String representation.
+     */
+    public String toString() {
+        StringBuffer buf = new StringBuffer();
+
+        for(int i=1; i < index; i++)
+            buf.append(i + ")" + constants[i] + "\n");
+
+        return buf.toString();
+    }
+
+    /** Import constant from another ConstantPool and return new index.
+     */
+    public int addConstant(Constant c, ConstantPoolGen cp) {
+        Constant[] constants = cp.getConstantPool().getConstantPool();
+
+        switch(c.getTag()) {
+            case Constants.CONSTANT_String: {
+                ConstantString s  = (ConstantString)c;
+                ConstantUtf8   u8 = (ConstantUtf8)constants[s.getStringIndex()];
+
+                return addString(u8.getBytes());
+            }
+
+            case Constants.CONSTANT_Class: {
+                ConstantClass s  = (ConstantClass)c;
+                ConstantUtf8  u8 = (ConstantUtf8)constants[s.getNameIndex()];
+
+                return addClass(u8.getBytes());
+            }
+
+            case Constants.CONSTANT_NameAndType: {
+                ConstantNameAndType n    = (ConstantNameAndType)c;
+                ConstantUtf8        u8   = (ConstantUtf8)constants[n.getNameIndex()];
+                ConstantUtf8        u8_2 = (ConstantUtf8)constants[n.getSignatureIndex()];
+
+                return addNameAndType(u8.getBytes(), u8_2.getBytes());
+            }
+
+            case Constants.CONSTANT_Utf8:
+                return addUtf8(((ConstantUtf8)c).getBytes());
+
+            case Constants.CONSTANT_Double:
+                return addDouble(((ConstantDouble)c).getBytes());
+
+            case Constants.CONSTANT_Float:
+                return addFloat(((ConstantFloat)c).getBytes());
+
+            case Constants.CONSTANT_Long:
+                return addLong(((ConstantLong)c).getBytes());
+
+            case Constants.CONSTANT_Integer:
+                return addInteger(((ConstantInteger)c).getBytes());
+
+            case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref:
+            case Constants.CONSTANT_Fieldref: {
+                ConstantCP          m     = (ConstantCP)c;
+                ConstantClass       clazz = (ConstantClass)constants[m.getClassIndex()];
+                ConstantNameAndType n     = (ConstantNameAndType)constants[m.getNameAndTypeIndex()];
+                ConstantUtf8 u8           = (ConstantUtf8)constants[clazz.getNameIndex()];
+                String       class_name   = u8.getBytes().replace('/', '.');
+
+                u8 = (ConstantUtf8)constants[n.getNameIndex()];
+                String name = u8.getBytes();
+
+                u8 = (ConstantUtf8)constants[n.getSignatureIndex()];
+                String signature = u8.getBytes();
+
+                switch(c.getTag()) {
+                    case Constants.CONSTANT_InterfaceMethodref:
+                        return addInterfaceMethodref(class_name, name, signature);
+
+                    case Constants.CONSTANT_Methodref:
+                        return addMethodref(class_name, name, signature);
+
+                    case Constants.CONSTANT_Fieldref:
+                        return addFieldref(class_name, name, signature);
+
+                    default: // Never reached
+                        throw new RuntimeException("Unknown constant type " + c);
+                }
+            }
+
+            default: // Never reached
+                throw new RuntimeException("Unknown constant type " + c);
+        }
+    }
+}