com.claritysys.jvm.classfile
Class ConstantPool

java.lang.Object
  extended by com.claritysys.jvm.classfile.ConstantPool

public final class ConstantPool
extends java.lang.Object

Models the java classfile constant pool, and provides the ability to dynamically construct or modify a constant pool.

The entries in the pool are all subclasses of CpEntry.

Constant pool management is the most time consuming aspect of compiling for the JVM, so it is crucial to performance that this portion of the API tread lightly on GC.

Towards this goal, the ConstantPool also implements its own hash table of its entries, internally, such that no extra objects need to be created. It also provides efficient searching operations for locating existing entries based on the hash view of the entries.

This work was significantly aided by the GNU-Bytecode package, written by Per Bothner, with which I worked for the 2 years heavily. The extensive use of implicit linked-lists, and the pool structure of entries plus hashing are modeled directly after GNU-Bytecode's technique.

This implementation also provides for "Java friendly" type declarations, encoded as strings starting with "@". While this is somewhat expensive for performance, it significantly aids readability for code generation.

Example:

    ConstantPool cp = new ConstantPool ();
    cp.addImport (Throwable.class);
    cp.addImport ("java/lang/System");
    cp.addMethodRef ("@Throwable.getMessage()String");
    cp.addFieldRef ("@System.out", "java/io/PrintStream");
 

Maintenance Notes

CpEntry.hash Cautionary Note -- The CpEntry.hash value is computed in each of the addXXX methods (eg, addValue1, addUtf8, etc). It is ALSO computed in the fromStream(DataInputStream) method. Both must use the same computation!


Constructor Summary
ConstantPool()
          Create a new, empty constant pool.
ConstantPool(boolean autoImport)
          Create a new, empty constant pool, with the default size, and automatically add all CpClass entries to the SigConverter import list.
ConstantPool(ConstantPool template)
          Create a new pool from the given template pool.
ConstantPool(int capacity)
          Create a new, empty constant pool with the given initial capacity.
 
Method Summary
 CpClass addClass(java.lang.Class cls)
          Search for the given Class in the CpClass entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpClass addClass(CpUtf8 name)
          Search for the given String in the Utf8 entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpClass addClass(java.lang.String name)
          Search for the given Class in the CpClass entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpValue2 addDouble(double val)
          Search for the given entry in the TAG_DOUBLE entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addFieldRef(CpClass clas, java.lang.String name, java.lang.String vmSig)
          Search for the given entry in the TAG_FIELDREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addFieldRef(int cpClassIndex, int nameIndex, int descriptorIndex)
          Build a methodref from the given class, name, and descriptor indexes.
 CpRef addFieldRef(java.lang.String className, java.lang.String name, java.lang.String vmSig)
          Search for the given entry in the TAG_FIELDREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addFieldRefJL(java.lang.String jlSig, java.lang.String classDotField)
          Add the given field reference to the pool, or find an existing reference.
 CpValue1 addFloat(float val)
          Search for the given entry in the TAG_FLOAT entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addIMethodRef(CpClass clas, java.lang.String name, java.lang.String sig)
          Search for the given entry in the TAG_INTERFACE_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addIMethodRef(java.lang.String className, java.lang.String name, java.lang.String sig)
          Search for the given entry in the TAG_INTERFACE_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 java.lang.String addImport(java.lang.Class clas)
          Add an important for the given class, so the "short" name can be used for method or field references.
 java.lang.String addImport(java.lang.String fqClassName)
          Add an important for the given class, so the "short" name can be used for method or field references.
 CpValue1 addInteger(int val)
          Search for the entry int in the TAG_INTEGER entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpClass addJavaClass(java.lang.String name)
          Search for the given Class in the CpClass entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpValue2 addLong(long val)
          Search for the given entry in the TAG_LONG entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addMethodRef(boolean isInterface, CpClass inClass, java.lang.String jlSig)
          A short form for adding CpRef's for methods.
 CpRef addMethodRef(boolean isInterface, CpClass cpClass, java.lang.String name, java.lang.String sig)
          Add CpRef method reference to constant pool, or find existing one.
 CpRef addMethodRef(boolean isInterface, java.lang.String clasName, java.lang.String name, java.lang.String sig)
          Search for the given entry in the TAG_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addMethodRef(CpClass clas, java.lang.String name, java.lang.String sig)
          Search for the given entry in the TAG_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addMethodRef(int cpClassIndex, int nameIndex, int descriptorIndex)
          Build a methodref from the given class, name, and descriptor indexes.
 CpNameAndType addNameAndType(CpUtf8 name, CpUtf8 type)
          Search for the given entry in the TAG_NAME_AND_TYPE entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpNameAndType addNameAndType(java.lang.String name, java.lang.String type)
          Search for the given entry in the TAG_NAME_AND_TYPE entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpRef addRef(byte tag, CpClass clas, CpNameAndType nameAndType)
          Search for the given entry in the [tag] entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpString addString(CpUtf8 str)
          Search for the given entry in the TAG_STRING entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpString addString(java.lang.String string)
          Search for the given entry in the TAG_STRING entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
 CpUtf8 addUtf8(java.lang.String s)
          Search for the given String in the Utf8 entries of the hashtable, returning the existing entry if found or adding a new entry if needed.
static ConstantPool fromStream(java.io.DataInputStream dataIn)
          Create a new ConstantPool by reading it from an input stream in the ClassFile format.
 int getCount()
          Return count of entries in pool.
 CpEntry getPoolEntry(int index)
          Get the index'th entry in pool.
 SigConverter getSigConverter()
          Get the (optional) SigConverter for converting from Java-friendly syntax to VM syntax.
 java.lang.String getUtf8AsString(int index)
          Get the index'th entry in the pool, cast it to a CpUtf8, and return its String value.
 boolean isAutoImport()
          Return whether auto import of class names is enabled.
 boolean isLocked()
          Return whether this pool has been 'locked' to any new entries.
 boolean isVerifyClassNames()
          Return whether class name verification is enabled..
 void setAutoImport(boolean autoImport)
          Set whether auto import of added classes is performed.
 void setLocked(boolean locked)
          Set this pool to be locked.
 void setVerifyClassNames(boolean verifyClassNames)
          Set whether class name verification is enabled.
 java.lang.String toString()
          Return a String description of the contents of this pool.
 void write(java.io.DataOutput dstr)
          Write pool to stream.
 void writeUTF(java.io.DataOutput out, java.lang.String str)
          Write the given string to the output stream as a UTF-8 sequence.
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Constructor Detail

ConstantPool

public ConstantPool()
Create a new, empty constant pool.

The size is defaulted to 239. If the size is known in advance (such as when reading from a disk image), use the constructor that specifies the size.


ConstantPool

public ConstantPool(boolean autoImport)
Create a new, empty constant pool, with the default size, and automatically add all CpClass entries to the SigConverter import list.

Parameters:
autoImport - If true all CpClass entries will automatically become imports.

ConstantPool

public ConstantPool(int capacity)
Create a new, empty constant pool with the given initial capacity.

Parameters:
capacity - The number of entries.

ConstantPool

public ConstantPool(ConstantPool template)
Create a new pool from the given template pool.

The entry[] and hashtables are copied and the entries are cloned, since they maintain their own hash links.

Method Detail

getCount

public int getCount()
Return count of entries in pool.

The last entry is at pool[count], since entry zero is null.

Returns:
number of entries, as well as index of last entry in pool.

getPoolEntry

public CpEntry getPoolEntry(int index)
Get the index'th entry in pool.

Parameters:
index - The pool entry index number.
Returns:
The CpEntry at the requested index.
Throws:
java.lang.ArrayIndexOutOfBoundsException - on an invalid index

getUtf8AsString

public java.lang.String getUtf8AsString(int index)
Get the index'th entry in the pool, cast it to a CpUtf8, and return its String value.

Parameters:
index - The pool entry index number.
Returns:
The value of the given (CpUtf8) entry as a String.
Throws:
java.lang.ClassCastException - If the entry at the requested index is NOT a CpUtf8.

addUtf8

public CpUtf8 addUtf8(java.lang.String s)
Search for the given String in the Utf8 entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
s - The string to find or add to the pool.
Returns:
Cputf8 for the requested string.

addClass

public CpClass addClass(java.lang.Class cls)
Search for the given Class in the CpClass entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

PERFORMANCE NOTE -- this creates intermediate string objects because it must convert between dot and slash format. For best performance use addClass(java.lang.String) and give it a proper VM signature such as "java/lang/Object".

Parameters:
cls - The Class object to add as a CpClass entry.
Returns:
The CpClass for the class.

addJavaClass

public CpClass addJavaClass(java.lang.String name)
Search for the given Class in the CpClass entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

The name should be in Java Language format, such as "java.lang.Object".

The method will convert "." into "/" as needed.

PERFORMANCE NOTE -- this creates intermediate string objects because it must convert between dot and slash format. For best performance use addClass(java.lang.String) and give it a proper VM signature such as "java/lang/Object".

Parameters:
name - Class name with dots instead of slashes, no leading "L".
Returns:
the existing / newly added CpClass entry.

addClass

public CpClass addClass(java.lang.String name)
Search for the given Class in the CpClass entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

PERFORMANCE NOTE -- for best performance use proper VM type signatures. Short-format signatures incur overhead and create intermediate string objects.

Parameters:
name - A name in either VM or short format. Both "java/lang/Object" and "@Object" are allowed here.
Returns:
The existing or newly added CpClass.

addClass

public CpClass addClass(CpUtf8 name)
Search for the given String in the Utf8 entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
name - The class name as a CpUtf8 entry.
Returns:
the existing or newly added CpClass entry.

addInteger

public CpValue1 addInteger(int val)
Search for the entry int in the TAG_INTEGER entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
val - The value to add as a CpValue1 (INTEGER) entry.
Returns:
The CpValue1 (INTEGER) for the requested constant integer.

addLong

public CpValue2 addLong(long val)
Search for the given entry in the TAG_LONG entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
val - The constant long value to add / find in the pool.
Returns:
The CpValue2 (LONG) constant entry.

addFloat

public CpValue1 addFloat(float val)
Search for the given entry in the TAG_FLOAT entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
val - The constant float value to add (or find) to the pool.
Returns:
The new or existing CpValue1 (FLOAT) constant entry.

addDouble

public CpValue2 addDouble(double val)
Search for the given entry in the TAG_DOUBLE entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
val - The constant double value to put in the pool.
Returns:
New or existing CpValue2 (DOUBLE) constant entry.

addString

public CpString addString(java.lang.String string)
Search for the given entry in the TAG_STRING entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
string - The string value to add / find in the pool.
Returns:
new or existing CpString for the given string constant.

addString

public CpString addString(CpUtf8 str)
Search for the given entry in the TAG_STRING entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
str - The CpUtf8 to add as a constant string.
Returns:
existing or new CpString entry.

addNameAndType

public CpNameAndType addNameAndType(CpUtf8 name,
                                    CpUtf8 type)
Search for the given entry in the TAG_NAME_AND_TYPE entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
name - Name portion of name and type, as CpUtf8.
type - Type portion of name and type, as CpUtf8.
Returns:
New or existing name and type entry.

addNameAndType

public CpNameAndType addNameAndType(java.lang.String name,
                                    java.lang.String type)
Search for the given entry in the TAG_NAME_AND_TYPE entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
name - Name portion of name and type.
type - Type portion of name and type. No short-form expansion is provided (I believe that's an oversight), the signature must be in VM format.
Returns:
New or existing name and type entry.

addRef

public CpRef addRef(byte tag,
                    CpClass clas,
                    CpNameAndType nameAndType)
Search for the given entry in the [tag] entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
tag - One of the CpEntry.TAG_XXX tags, for the proper type of ref to add (field, method, interface method).
clas - the class portion of the CpRef.
nameAndType - name and type.
Returns:
New or existing CpRef.

addMethodRef

public CpRef addMethodRef(boolean isInterface,
                          java.lang.String clasName,
                          java.lang.String name,
                          java.lang.String sig)
Search for the given entry in the TAG_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
isInterface - true if a TAG_INTERFACE_METHODREF is desired, false for TAG_METHODREF.
clasName - A class name in either VM "java/lang/String" or JLS "@String" format. Note it MUST be in "/" format if it doesn't start with an "@" character!
name - Method name.
sig - Signature in either VM "(Ljava/lang/String;)V" or JLS "@(String)" format.
Returns:
Existing or newly added method ref.

addMethodRef

public CpRef addMethodRef(boolean isInterface,
                          CpClass cpClass,
                          java.lang.String name,
                          java.lang.String sig)
Add CpRef method reference to constant pool, or find existing one.

Parameters:
isInterface - true for TAG_INTERFACE_METHODREF, false for TAG_METHODREF.
cpClass - The class (or interface) in which to invoke the method.
name - Method name.
sig - Signature in either VM "(Ljava/lang/String;)V" or JLS "@(String)" format.
Returns:
Existing or newly added method ref.

addMethodRef

public CpRef addMethodRef(boolean isInterface,
                          CpClass inClass,
                          java.lang.String jlSig)
A short form for adding CpRef's for methods.

Unlike other methods, this one ONLY supports short-format signatures such as "@Object.getString()String". The optional inClass parameter allows the caller to pass a class to be used in case none is specified in the signature (eg, "@getString()String"). This makes it easy in the CodeBuilder to implement support for an implicit "this".

Examples:

   pool.addMethodRef (true, null, "@ResultSet.getInt(int)int");
   pool.addMethodRef (false, OBJECT, "@getString()String");
 

Parameters:
isInterface - True if a INTERFACE_METHODREF is desired, false if METHODREF is desired.
inClass - Optional class to invoke method in, if none is given in the signature.
jlSig - A method signature, optionally with a class. It MUST begin with an @ character.
Returns:
New or existing CpRef entry.

addMethodRef

public CpRef addMethodRef(CpClass clas,
                          java.lang.String name,
                          java.lang.String sig)
Search for the given entry in the TAG_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
clas - Class in which to invoke method, as a CpClass.
name - Method name.
sig - Signature, in VM or '@' format.
Returns:
CpRef METHODREF.

addMethodRef

public CpRef addMethodRef(int cpClassIndex,
                          int nameIndex,
                          int descriptorIndex)
Build a methodref from the given class, name, and descriptor indexes.

Parameters:
cpClassIndex - CpClass index.
nameIndex - CpUtf8 index for name.
descriptorIndex - CpUtf8 index for signature.
Returns:
CpRef for METHODREF.

addIMethodRef

public CpRef addIMethodRef(java.lang.String className,
                           java.lang.String name,
                           java.lang.String sig)
Search for the given entry in the TAG_INTERFACE_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Adds an INTERFACE_METHODREF CpRef entry.

See Also:
#addMethodRef(boolean, java.lang.String, java.lang.String, java.lang.String)}.

addIMethodRef

public CpRef addIMethodRef(CpClass clas,
                           java.lang.String name,
                           java.lang.String sig)
Search for the given entry in the TAG_INTERFACE_METHODREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Adds an INTERFACE_METHODREF CpRef entry.

See Also:
#addMethodRef(boolean, com.claritysys.jvm.classfile.CpClass, java.lang.String, java.lang.String)}

addFieldRef

public CpRef addFieldRef(java.lang.String className,
                         java.lang.String name,
                         java.lang.String vmSig)
Search for the given entry in the TAG_FIELDREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
className - Class in which field is declared, in short '@' format or VM format.
name - field name.
vmSig - Signature in VM format. Sorry, no '@' support here.
Returns:

addFieldRef

public CpRef addFieldRef(CpClass clas,
                         java.lang.String name,
                         java.lang.String vmSig)
Search for the given entry in the TAG_FIELDREF entries of the hashtable, returning the existing entry if found or adding a new entry if needed.

Parameters:
clas - Class in which field is declared.
name - field name.
vmSig - Signature in VM format. Sorry, no '@' support here.
Returns:

addFieldRef

public CpRef addFieldRef(int cpClassIndex,
                         int nameIndex,
                         int descriptorIndex)
Build a methodref from the given class, name, and descriptor indexes.

Parameters:
cpClassIndex - Index for CpClass in which field is declared.
nameIndex - CpUtf8 index for field name.
descriptorIndex - CpUtf8 index for field signature.
Returns:

addFieldRefJL

public CpRef addFieldRefJL(java.lang.String jlSig,
                           java.lang.String classDotField)
Add the given field reference to the pool, or find an existing reference.

Parameters:
jlSig - Field signature in '@' format. MUST HAVE LEADING '@'.
classDotField - Class and field in '@' format, such as '@Class.field'.
Returns:

getSigConverter

public SigConverter getSigConverter()
Get the (optional) SigConverter for converting from Java-friendly syntax to VM syntax. The converter is created on the first call to this method.

Returns:
The SigConverter

addImport

public java.lang.String addImport(java.lang.String fqClassName)
Add an important for the given class, so the "short" name can be used for method or field references.

This makes the name available for the JLS-type signatures such as "@Object.getClass()Class". In order for it to understand that "Object" means "java/lang/Object" there must be an import that maps the short name to the full name.

Imports can be added manually, by calling this method, or automatically by setting autoImport to true. Then all added CpClass entries become imports.

Parameters:
fqClassName - Class name in either dot or slash format. The SigConverter may also allow the "Lpath;" form.
Returns:
the short name for the class.
See Also:
SigConverter#addImport}

addImport

public java.lang.String addImport(java.lang.Class clas)
Add an important for the given class, so the "short" name can be used for method or field references.

This makes the name available for the JLS-type signatures such as "@Object.getClass()Class". In order for it to understand that "Object" means "java/lang/Object" there must be an import that maps the short name to the full name.

Imports can be added manually, by calling this method, or automatically by setting autoImport to true. Then all added CpClass entries become imports.

Parameters:
clas - The class to add.
Returns:
the short name for the class.
See Also:
SigConverter#addImport}

isLocked

public boolean isLocked()
Return whether this pool has been 'locked' to any new entries.

Returns:
true if locked, eg if addEntry will throw an exception.
See Also:
#setLocked}.

setLocked

public void setLocked(boolean locked)
Set this pool to be locked.

Any attempt to add entries to the pool will throw an error if locked.

Parameters:
locked - true to lock the pool to new entries, false to unlock it.

write

public void write(java.io.DataOutput dstr)
           throws java.io.IOException
Write pool to stream.

Throws:
java.io.IOException

fromStream

public static ConstantPool fromStream(java.io.DataInputStream dataIn)
                               throws java.io.IOException,
                                      ClassFileFormatException
Create a new ConstantPool by reading it from an input stream in the ClassFile format.

It reads only the constant pool and leaves the stream open, so this method can be used to read the constant pool while also reading the whole class file.

NOTE: The CpEntry.hash values are created here, and the code is duplicated from all the addXXX methods. Be very careful when changing the hash computation to change it in both places!

Parameters:
dataIn -
Returns:
New constant pool, as read from dataIn.
Throws:
java.io.IOException
ClassFileFormatException

toString

public java.lang.String toString()
Return a String description of the contents of this pool.

Writes all entries to the string.

Overrides:
toString in class java.lang.Object

writeUTF

public void writeUTF(java.io.DataOutput out,
                     java.lang.String str)
              throws java.io.IOException
Write the given string to the output stream as a UTF-8 sequence.

Java often specifies UTF-8 as the encoding but completely lacks any efficient means for conversion between String and Utf-8 sequences. This implementation is significantly faster than using the one in DataOutput, which creates ridiculous amounts of objects.

TODO: This method relies on internal byte and char buffers in ConstantPool that should be put somewhere else to save memory when writing many class files.

Parameters:
out -
str -
Throws:
java.io.IOException

isVerifyClassNames

public boolean isVerifyClassNames()
Return whether class name verification is enabled..

Returns:

setVerifyClassNames

public void setVerifyClassNames(boolean verifyClassNames)
Set whether class name verification is enabled.

If enabled, all CpClass entries are verified to be proper VM formatted signatures. This can really help to debug a program which is adding JLS formed signatures, which is easy to accidentally do via addClass (SomeClass.getName ()) (which is not allowed).

Parameters:
verifyClassNames -

isAutoImport

public boolean isAutoImport()
Return whether auto import of class names is enabled.

Returns:

setAutoImport

public void setAutoImport(boolean autoImport)
Set whether auto import of added classes is performed.

If enabled, then once a class is added it can be referenced simply as '@Class'. For example, if the class "some/package/SomeClass" is added, and autoImport is true, then from that point on it can be referenced as "@SomeClass".

If enabled after entries are added it does NOT process existing entries.

Parameters:
autoImport -


Copyright ? 2000-2003 Clarity Systems Group, LLC. All Rights Reserved.