public final class ConstantPool
extends java.lang.Object
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");
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 and Description |
---|
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.
|
Modifier and Type | Method and Description |
---|---|
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.
|
public ConstantPool()
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.
public ConstantPool(boolean autoImport)
autoImport
- If true all CpClass entries will automatically become
imports.public ConstantPool(int capacity)
capacity
- The number of entries.public ConstantPool(ConstantPool template)
The entry[] and hashtables are copied and the entries are cloned, since they maintain their own hash links.
public int getCount()
The last entry is at pool[count], since entry zero is null.
public CpEntry getPoolEntry(int index)
index
- The pool entry index number.java.lang.ArrayIndexOutOfBoundsException
- on an invalid indexpublic java.lang.String getUtf8AsString(int index)
index
- The pool entry index number.java.lang.ClassCastException
- If the entry at the requested index is NOT
a CpUtf8.public CpUtf8 addUtf8(java.lang.String s)
s
- The string to find or add to the pool.public CpClass addClass(java.lang.Class cls)
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".
cls
- The Class object to add as a CpClass entry.public CpClass addJavaClass(java.lang.String name)
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".
name
- Class name with dots instead of slashes, no leading "L".public CpClass addClass(java.lang.String name)
PERFORMANCE NOTE -- for best performance use proper VM type signatures. Short-format signatures incur overhead and create intermediate string objects.
name
- A name in either VM or short format. Both "java/lang/Object"
and "@Object" are allowed here.public CpClass addClass(CpUtf8 name)
name
- The class name as a CpUtf8 entry.public CpValue1 addInteger(int val)
val
- The value to add as a CpValue1 (INTEGER) entry.public CpValue2 addLong(long val)
val
- The constant long value to add / find in the pool.public CpValue1 addFloat(float val)
val
- The constant float value to add (or find) to the pool.public CpValue2 addDouble(double val)
val
- The constant double value to put in the pool.public CpString addString(java.lang.String string)
string
- The string value to add / find in the pool.public CpString addString(CpUtf8 str)
str
- The CpUtf8 to add as a constant string.public CpNameAndType addNameAndType(CpUtf8 name, CpUtf8 type)
name
- Name portion of name and type, as CpUtf8.type
- Type portion of name and type, as CpUtf8.public CpNameAndType addNameAndType(java.lang.String name, java.lang.String type)
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.public CpRef addRef(byte tag, CpClass clas, CpNameAndType nameAndType)
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.public CpRef addMethodRef(boolean isInterface, java.lang.String clasName, java.lang.String name, java.lang.String sig)
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.public CpRef addMethodRef(boolean isInterface, CpClass cpClass, java.lang.String name, java.lang.String sig)
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.public CpRef addMethodRef(boolean isInterface, CpClass inClass, java.lang.String jlSig)
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");
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.public CpRef addMethodRef(CpClass clas, java.lang.String name, java.lang.String sig)
clas
- Class in which to invoke method, as a CpClass.name
- Method name.sig
- Signature, in VM or '@' format.public CpRef addMethodRef(int cpClassIndex, int nameIndex, int descriptorIndex)
cpClassIndex
- CpClass index.nameIndex
- CpUtf8 index for name.descriptorIndex
- CpUtf8 index for signature.public CpRef addIMethodRef(java.lang.String className, java.lang.String name, java.lang.String sig)
Adds an INTERFACE_METHODREF CpRef entry.
#addMethodRef(boolean, java.lang.String, java.lang.String, java.lang.String)}.
public CpRef addIMethodRef(CpClass clas, java.lang.String name, java.lang.String sig)
Adds an INTERFACE_METHODREF CpRef entry.
#addMethodRef(boolean, com.claritysys.jvm.classfile.CpClass, java.lang.String, java.lang.String)}
public CpRef addFieldRef(java.lang.String className, java.lang.String name, java.lang.String vmSig)
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.public CpRef addFieldRef(CpClass clas, java.lang.String name, java.lang.String vmSig)
clas
- Class in which field is declared.name
- field name.vmSig
- Signature in VM format. Sorry, no '@' support here.public CpRef addFieldRef(int cpClassIndex, int nameIndex, int descriptorIndex)
cpClassIndex
- Index for CpClass in which field is declared.nameIndex
- CpUtf8 index for field name.descriptorIndex
- CpUtf8 index for field signature.public CpRef addFieldRefJL(java.lang.String jlSig, java.lang.String classDotField)
jlSig
- Field signature in '@' format. MUST HAVE LEADING '@'.classDotField
- Class and field in '@' format, such as
'@Class.field'.public SigConverter getSigConverter()
public java.lang.String addImport(java.lang.String fqClassName)
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.
fqClassName
- Class name in either dot or slash format. The
SigConverter may also allow the "Lpath;" form.SigConverter#addImport}
public java.lang.String addImport(java.lang.Class clas)
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.
clas
- The class to add.SigConverter#addImport}
public boolean isLocked()
#setLocked}.
public void setLocked(boolean locked)
Any attempt to add entries to the pool will throw an error if locked.
locked
- true to lock the pool to new entries, false to unlock it.public void write(java.io.DataOutput dstr) throws java.io.IOException
java.io.IOException
public static ConstantPool fromStream(java.io.DataInputStream dataIn) throws java.io.IOException, ClassFileFormatException
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!
dataIn
- java.io.IOException
ClassFileFormatException
public java.lang.String toString()
Writes all entries to the string.
toString
in class java.lang.Object
public void writeUTF(java.io.DataOutput out, java.lang.String str) throws java.io.IOException
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.
out
- str
- java.io.IOException
public boolean isVerifyClassNames()
public void setVerifyClassNames(boolean verifyClassNames)
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).
verifyClassNames
- public boolean isAutoImport()
public void setAutoImport(boolean autoImport)
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.
autoImport
- Copyright ? 2000-2003 Clarity Systems Group, LLC. All Rights Reserved.