/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist.bytecode;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import javassist.CtClass;
/**
* Constant pool table.
*/
public final class ConstPool {
LongVector items;
int numOfItems;
HashMap classes;
HashMap strings;
int thisClassInfo;
/**
* CONSTANT_Class
*/
public static final int CONST_Class = ClassInfo.tag;
/**
* CONSTANT_Fieldref
*/
public static final int CONST_Fieldref = FieldrefInfo.tag;
/**
* CONSTANT_Methodref
*/
public static final int CONST_Methodref = MethodrefInfo.tag;
/**
* CONSTANT_InterfaceMethodref
*/
public static final int CONST_InterfaceMethodref
= InterfaceMethodrefInfo.tag;
/**
* CONSTANT_String
*/
public static final int CONST_String = StringInfo.tag;
/**
* CONSTANT_Integer
*/
public static final int CONST_Integer = IntegerInfo.tag;
/**
* CONSTANT_Float
*/
public static final int CONST_Float = FloatInfo.tag;
/**
* CONSTANT_Long
*/
public static final int CONST_Long = LongInfo.tag;
/**
* CONSTANT_Double
*/
public static final int CONST_Double = DoubleInfo.tag;
/**
* CONSTANT_NameAndType
*/
public static final int CONST_NameAndType = NameAndTypeInfo.tag;
/**
* CONSTANT_Utf8
*/
public static final int CONST_Utf8 = Utf8Info.tag;
/**
* Represents the class using this constant pool table.
*/
public static final CtClass THIS = null;
/**
* Constructs a constant pool table.
*
* @param thisclass the name of the class using this constant
* pool table
*/
public ConstPool(String thisclass) {
items = new LongVector();
numOfItems = 0;
addItem(null); // index 0 is reserved by the JVM.
classes = new HashMap();
strings = new HashMap();
thisClassInfo = addClassInfo(thisclass);
}
/**
* Constructs a constant pool table from the given byte stream.
*
* @param in byte stream.
*/
public ConstPool(DataInputStream in) throws IOException {
classes = new HashMap();
strings = new HashMap();
thisClassInfo = 0;
/* read() initializes items and numOfItems, and do addItem(null).
*/
read(in);
}
void prune() {
classes = new HashMap();
strings = new HashMap();
}
/**
* Returns the name of the class using this constant pool table.
*/
public String getClassName() {
return getClassInfo(thisClassInfo);
}
/**
* Returns the index of CONSTANT_Class_info
structure
* specifying the class using this constant pool table.
*/
public int getThisClassInfo() {
return thisClassInfo;
}
void setThisClassInfo(int i) {
thisClassInfo = i;
}
ConstInfo getItem(int n) {
return (ConstInfo)items.elementAt(n);
}
/**
* Returns the tag
field of the constant pool table
* entry at the given index.
*/
public int getTag(int index) {
return getItem(index).getTag();
}
/**
* Reads CONSTANT_Class_info
structure
* at the given index.
*
* @return a fully-qualified class or interface name specified
* by name_index
.
*/
public String getClassInfo(int index) {
ClassInfo c = (ClassInfo)getItem(index);
if (c == null)
return null;
else
return Descriptor.toJavaName(getUtf8Info(c.name));
}
/**
* Reads the name_index
field of the
* CONSTANT_NameAndType_info
structure
* at the given index.
*/
public int getNameAndTypeName(int index) {
NameAndTypeInfo ntinfo = (NameAndTypeInfo)getItem(index);
return ntinfo.memberName;
}
/**
* Reads the descriptor_index
field of the
* CONSTANT_NameAndType_info
structure
* at the given index.
*/
public int getNameAndTypeDescriptor(int index) {
NameAndTypeInfo ntinfo = (NameAndTypeInfo)getItem(index);
return ntinfo.typeDescriptor;
}
/**
* Reads the class_index
field of the
* CONSTANT_Fieldref_info
structure
* at the given index.
*/
public int getFieldrefClass(int index) {
FieldrefInfo finfo = (FieldrefInfo)getItem(index);
return finfo.classIndex;
}
/**
* Reads the class_index
field of the
* CONSTANT_Fieldref_info
structure
* at the given index.
*
* @return the name of the class at that class_index
.
*/
public String getFieldrefClassName(int index) {
FieldrefInfo f = (FieldrefInfo)getItem(index);
if (f == null)
return null;
else
return getClassInfo(f.classIndex);
}
/**
* Reads the name_and_type_index
field of the
* CONSTANT_Fieldref_info
structure
* at the given index.
*/
public int getFieldrefNameAndType(int index) {
FieldrefInfo finfo = (FieldrefInfo)getItem(index);
return finfo.nameAndTypeIndex;
}
/**
* Reads the name_index
field of the
* CONSTANT_NameAndType_info
structure
* indirectly specified by the given index.
*
* @param index an index to a CONSTANT_Fieldref_info
.
* @return the name of the field.
*/
public String getFieldrefName(int index) {
FieldrefInfo f = (FieldrefInfo)getItem(index);
if (f == null)
return null;
else {
NameAndTypeInfo n = (NameAndTypeInfo)getItem(f.nameAndTypeIndex);
if(n == null)
return null;
else
return getUtf8Info(n.memberName);
}
}
/**
* Reads the descriptor_index
field of the
* CONSTANT_NameAndType_info
structure
* indirectly specified by the given index.
*
* @param index an index to a CONSTANT_Fieldref_info
.
* @return the type descriptor of the field.
*/
public String getFieldrefType(int index) {
FieldrefInfo f = (FieldrefInfo)getItem(index);
if (f == null)
return null;
else {
NameAndTypeInfo n = (NameAndTypeInfo) getItem(f.nameAndTypeIndex);
if(n == null)
return null;
else
return getUtf8Info(n.typeDescriptor);
}
}
/**
* Reads the class_index
field of the
* CONSTANT_Methodref_info
structure
* at the given index.
*/
public int getMethodrefClass(int index) {
MethodrefInfo minfo = (MethodrefInfo)getItem(index);
return minfo.classIndex;
}
/**
* Reads the class_index
field of the
* CONSTANT_Methodref_info
structure
* at the given index.
*
* @return the name of the class at that class_index
.
*/
public String getMethodrefClassName(int index) {
MethodrefInfo minfo = (MethodrefInfo)getItem(index);
if (minfo == null)
return null;
else
return getClassInfo(minfo.classIndex);
}
/**
* Reads the name_and_type_index
field of the
* CONSTANT_Methodref_info
structure
* at the given index.
*/
public int getMethodrefNameAndType(int index) {
MethodrefInfo minfo = (MethodrefInfo)getItem(index);
return minfo.nameAndTypeIndex;
}
/**
* Reads the name_index
field of the
* CONSTANT_NameAndType_info
structure
* indirectly specified by the given index.
*
* @param index an index to a CONSTANT_Methodref_info
.
* @return the name of the method.
*/
public String getMethodrefName(int index) {
MethodrefInfo minfo = (MethodrefInfo)getItem(index);
if (minfo == null)
return null;
else {
NameAndTypeInfo n
= (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
if(n == null)
return null;
else
return getUtf8Info(n.memberName);
}
}
/**
* Reads the descriptor_index
field of the
* CONSTANT_NameAndType_info
structure
* indirectly specified by the given index.
*
* @param index an index to a CONSTANT_Methodref_info
.
* @return the descriptor of the method.
*/
public String getMethodrefType(int index) {
MethodrefInfo minfo = (MethodrefInfo)getItem(index);
if (minfo == null)
return null;
else {
NameAndTypeInfo n
= (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
if(n == null)
return null;
else
return getUtf8Info(n.typeDescriptor);
}
}
/**
* Reads the class_index
field of the
* CONSTANT_InterfaceMethodref_info
structure
* at the given index.
*/
public int getInterfaceMethodrefClass(int index) {
InterfaceMethodrefInfo minfo
= (InterfaceMethodrefInfo)getItem(index);
return minfo.classIndex;
}
/**
* Reads the class_index
field of the
* CONSTANT_InterfaceMethodref_info
structure
* at the given index.
*
* @return the name of the class at that class_index
.
*/
public String getInterfaceMethodrefClassName(int index) {
InterfaceMethodrefInfo minfo
= (InterfaceMethodrefInfo)getItem(index);
return getClassInfo(minfo.classIndex);
}
/**
* Reads the name_and_type_index
field of the
* CONSTANT_InterfaceMethodref_info
structure
* at the given index.
*/
public int getInterfaceMethodrefNameAndType(int index) {
InterfaceMethodrefInfo minfo
= (InterfaceMethodrefInfo)getItem(index);
return minfo.nameAndTypeIndex;
}
/**
* Reads the name_index
field of the
* CONSTANT_NameAndType_info
structure
* indirectly specified by the given index.
*
* @param index an index to
* a CONSTANT_InterfaceMethodref_info
.
* @return the name of the method.
*/
public String getInterfaceMethodrefName(int index) {
InterfaceMethodrefInfo minfo
= (InterfaceMethodrefInfo)getItem(index);
if (minfo == null)
return null;
else {
NameAndTypeInfo n
= (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
if(n == null)
return null;
else
return getUtf8Info(n.memberName);
}
}
/**
* Reads the descriptor_index
field of the
* CONSTANT_NameAndType_info
structure
* indirectly specified by the given index.
*
* @param index an index to
* a CONSTANT_InterfaceMethodref_info
.
* @return the descriptor of the method.
*/
public String getInterfaceMethodrefType(int index) {
InterfaceMethodrefInfo minfo
= (InterfaceMethodrefInfo)getItem(index);
if (minfo == null)
return null;
else {
NameAndTypeInfo n
= (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
if(n == null)
return null;
else
return getUtf8Info(n.typeDescriptor);
}
}
/**
* Reads CONSTANT_Integer_info
, _Float_info
,
* _Long_info
, _Double_info
, or
* _String_info
structure.
* These are used with the LDC instruction.
*
* @return a String
value or a wrapped primitive-type
* value.
*/
public Object getLdcValue(int index) {
ConstInfo constInfo = this.getItem(index);
Object value = null;
if (constInfo instanceof StringInfo)
value = this.getStringInfo(index);
else if (constInfo instanceof FloatInfo)
value = new Float(getFloatInfo(index));
else if (constInfo instanceof IntegerInfo)
value = new Integer(getIntegerInfo(index));
else if (constInfo instanceof LongInfo)
value = new Long(getLongInfo(index));
else if (constInfo instanceof DoubleInfo)
value = new Double(getDoubleInfo(index));
else
value = null;
return value;
}
/**
* Reads CONSTANT_Integer_info
structure
* at the given index.
*
* @return the value specified by this entry.
*/
public int getIntegerInfo(int index) {
IntegerInfo i = (IntegerInfo)getItem(index);
return i.value;
}
/**
* Reads CONSTANT_Float_info
structure
* at the given index.
*
* @return the value specified by this entry.
*/
public float getFloatInfo(int index) {
FloatInfo i = (FloatInfo)getItem(index);
return i.value;
}
/**
* Reads CONSTANT_Long_info
structure
* at the given index.
*
* @return the value specified by this entry.
*/
public long getLongInfo(int index) {
LongInfo i = (LongInfo)getItem(index);
return i.value;
}
/**
* Reads CONSTANT_Double_info
structure
* at the given index.
*
* @return the value specified by this entry.
*/
public double getDoubleInfo(int index) {
DoubleInfo i = (DoubleInfo)getItem(index);
return i.value;
}
/**
* Reads CONSTANT_String_info
structure
* at the given index.
*
* @return the string specified by string_index
.
*/
public String getStringInfo(int index) {
StringInfo si = (StringInfo)getItem(index);
return getUtf8Info(si.string);
}
/**
* Reads CONSTANT_utf8_info
structure
* at the given index.
*
* @return the string specified by this entry.
*/
public String getUtf8Info(int index) {
Utf8Info utf = (Utf8Info)getItem(index);
return utf.string;
}
/**
* Determines whether CONSTANT_Methodref_info
* structure at the given index represents the constructor
* of the given class.
*
* @return the descriptor_index
specifying
* the type descriptor of the that constructor.
* If it is not that constructor,
* isConstructor()
returns 0.
*/
public int isConstructor(String classname, int index) {
return isMember(classname, MethodInfo.nameInit, index);
}
/**
* Determines whether CONSTANT_Methodref_info
,
* CONSTANT_Fieldref_info
, or
* CONSTANT_InterfaceMethodref_info
structure
* at the given index represents the member with the specified
* name and declaring class.
*
* @param classname the class declaring the member
* @param membername the member name
* @param index the index into the constant pool table
*
* @return the descriptor_index
specifying
* the type descriptor of that member.
* If it is not that member,
* isMember()
returns 0.
*/
public int isMember(String classname, String membername, int index) {
MemberrefInfo minfo = (MemberrefInfo)getItem(index);
if (getClassInfo(minfo.classIndex).equals(classname)) {
NameAndTypeInfo ntinfo
= (NameAndTypeInfo)getItem(minfo.nameAndTypeIndex);
if (getUtf8Info(ntinfo.memberName).equals(membername))
return ntinfo.typeDescriptor;
}
return 0; // false
}
private int addItem(ConstInfo info) {
items.addElement(info);
return numOfItems++;
}
/**
* Copies the n-th item in this ConstPool object into the destination
* ConstPool object.
* The class names that the item refers to are renamed according
* to the given map.
*
* @param n the n-th item
* @param dest destination constant pool table
* @param classnames the map or null.
* @return the index of the copied item into the destination ClassPool.
*/
public int copy(int n, ConstPool dest, Map classnames) {
if (n == 0)
return 0;
ConstInfo info = getItem(n);
return info.copy(this, dest, classnames);
}
int addConstInfoPadding() {
return addItem(new ConstInfoPadding());
}
/**
* Adds a new CONSTANT_Class_info
structure.
*
*
This also adds a This also adds a This also adds This also adds a new This also adds a new This also adds a new This also adds a new If the given utf8 string has been already recorded in the
* table, then this method does not add a new entry to avoid adding
* a duplicated entry.
* Instead, it returns the index of the entry already recorded.
*
* @return the index of the added entry.
*/
public int addUtf8Info(String utf8) {
Utf8Info info = (Utf8Info)strings.get(utf8);
if (info != null)
return info.index;
else {
info = new Utf8Info(utf8, numOfItems);
strings.put(utf8, info);
return addItem(info);
}
}
/**
* Get all the class names
*
* @return a set of class names
*/
public Set getClassNames()
{
HashSet result = new HashSet();
LongVector v = items;
int size = numOfItems;
for (int i = 1; i < size; ++i)
{
String className = ((ConstInfo) v.elementAt(i)).getClassName(this);
if (className != null)
result.add(className);
}
return result;
}
/**
* Replaces all occurrences of a class name.
*
* @param oldName the replaced name
* @param newName the substituted name.
*/
public void renameClass(String oldName, String newName) {
LongVector v = items;
int size = numOfItems;
for (int i = 1; i < size; ++i)
((ConstInfo)v.elementAt(i)).renameClass(this, oldName, newName);
}
/**
* Replaces all occurrences of class names.
*
* @param classnames specifies pairs of replaced and substituted
* name.
*/
public void renameClass(Map classnames) {
LongVector v = items;
int size = numOfItems;
for (int i = 1; i < size; ++i)
((ConstInfo)v.elementAt(i)).renameClass(this, classnames);
}
private void read(DataInputStream in) throws IOException {
int n = in.readUnsignedShort();
int size = (n / LongVector.SIZE + 1) * LongVector.SIZE;
items = new LongVector(size);
numOfItems = 0;
addItem(null); // index 0 is reserved by the JVM.
while (--n > 0) { // index 0 is reserved by JVM
int tag = readOne(in);
if ((tag == LongInfo.tag) || (tag == DoubleInfo.tag)) {
addItem(new ConstInfoPadding());
--n;
}
}
}
private int readOne(DataInputStream in) throws IOException {
ConstInfo info;
int tag = in.readUnsignedByte();
switch (tag) {
case Utf8Info.tag : // 1
info = new Utf8Info(in, numOfItems);
strings.put(((Utf8Info)info).string, info);
break;
case IntegerInfo.tag : // 3
info = new IntegerInfo(in);
break;
case FloatInfo.tag : // 4
info = new FloatInfo(in);
break;
case LongInfo.tag : // 5
info = new LongInfo(in);
break;
case DoubleInfo.tag : // 6
info = new DoubleInfo(in);
break;
case ClassInfo.tag : // 7
info = new ClassInfo(in, numOfItems);
// classes.put(CONSTANT_Utf8_info
structure
* for storing the class name.
*
* @return the index of the added entry.
*/
public int addClassInfo(CtClass c) {
if (c == THIS)
return thisClassInfo;
else if (!c.isArray())
return addClassInfo(c.getName());
else {
// an array type is recorded in the hashtable with
// the key "[LCONSTANT_Class_info
structure.
*
* CONSTANT_Utf8_info
structure
* for storing the class name.
*
* @param qname a fully-qualified class name
* (or the JVM-internal representation of that name).
* @return the index of the added entry.
*/
public int addClassInfo(String qname) {
ClassInfo info = (ClassInfo)classes.get(qname);
if (info != null)
return info.index;
else {
int utf8 = addUtf8Info(Descriptor.toJvmName(qname));
info = new ClassInfo(utf8, numOfItems);
classes.put(qname, info);
return addItem(info);
}
}
/**
* Adds a new CONSTANT_NameAndType_info
structure.
*
* CONSTANT_Utf8_info
structures.
*
* @param name name_index
* @param type descriptor_index
* @return the index of the added entry.
*/
public int addNameAndTypeInfo(String name, String type) {
return addNameAndTypeInfo(addUtf8Info(name), addUtf8Info(type));
}
/**
* Adds a new CONSTANT_NameAndType_info
structure.
*
* @param name name_index
* @param type descriptor_index
* @return the index of the added entry.
*/
public int addNameAndTypeInfo(int name, int type) {
return addItem(new NameAndTypeInfo(name, type));
}
/**
* Adds a new CONSTANT_Fieldref_info
structure.
*
* CONSTANT_NameAndType_info
* structure.
*
* @param classInfo class_index
* @param name name_index
* of CONSTANT_NameAndType_info
.
* @param type descriptor_index
* of CONSTANT_NameAndType_info
.
* @return the index of the added entry.
*/
public int addFieldrefInfo(int classInfo, String name, String type) {
int nt = addNameAndTypeInfo(name, type);
return addFieldrefInfo(classInfo, nt);
}
/**
* Adds a new CONSTANT_Fieldref_info
structure.
*
* @param classInfo class_index
* @param nameAndTypeInfo name_and_type_index
.
* @return the index of the added entry.
*/
public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) {
return addItem(new FieldrefInfo(classInfo, nameAndTypeInfo));
}
/**
* Adds a new CONSTANT_Methodref_info
structure.
*
* CONSTANT_NameAndType_info
* structure.
*
* @param classInfo class_index
* @param name name_index
* of CONSTANT_NameAndType_info
.
* @param type descriptor_index
* of CONSTANT_NameAndType_info
.
* @return the index of the added entry.
*/
public int addMethodrefInfo(int classInfo, String name, String type) {
int nt = addNameAndTypeInfo(name, type);
return addMethodrefInfo(classInfo, nt);
}
/**
* Adds a new CONSTANT_Methodref_info
structure.
*
* @param classInfo class_index
* @param nameAndTypeInfo name_and_type_index
.
* @return the index of the added entry.
*/
public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) {
return addItem(new MethodrefInfo(classInfo, nameAndTypeInfo));
}
/**
* Adds a new CONSTANT_InterfaceMethodref_info
* structure.
*
* CONSTANT_NameAndType_info
* structure.
*
* @param classInfo class_index
* @param name name_index
* of CONSTANT_NameAndType_info
.
* @param type descriptor_index
* of CONSTANT_NameAndType_info
.
* @return the index of the added entry.
*/
public int addInterfaceMethodrefInfo(int classInfo, String name,
String type) {
int nt = addNameAndTypeInfo(name, type);
return addInterfaceMethodrefInfo(classInfo, nt);
}
/**
* Adds a new CONSTANT_InterfaceMethodref_info
* structure.
*
* @param classInfo class_index
* @param nameAndTypeInfo name_and_type_index
.
* @return the index of the added entry.
*/
public int addInterfaceMethodrefInfo(int classInfo,
int nameAndTypeInfo) {
return addItem(new InterfaceMethodrefInfo(classInfo,
nameAndTypeInfo));
}
/**
* Adds a new CONSTANT_String_info
* structure.
*
* CONSTANT_Utf8_info
* structure.
*
* @return the index of the added entry.
*/
public int addStringInfo(String str) {
return addItem(new StringInfo(addUtf8Info(str)));
}
/**
* Adds a new CONSTANT_Integer_info
* structure.
*
* @return the index of the added entry.
*/
public int addIntegerInfo(int i) {
return addItem(new IntegerInfo(i));
}
/**
* Adds a new CONSTANT_Float_info
* structure.
*
* @return the index of the added entry.
*/
public int addFloatInfo(float f) {
return addItem(new FloatInfo(f));
}
/**
* Adds a new CONSTANT_Long_info
* structure.
*
* @return the index of the added entry.
*/
public int addLongInfo(long l) {
int i = addItem(new LongInfo(l));
addItem(new ConstInfoPadding());
return i;
}
/**
* Adds a new CONSTANT_Double_info
* structure.
*
* @return the index of the added entry.
*/
public int addDoubleInfo(double d) {
int i = addItem(new DoubleInfo(d));
addItem(new ConstInfoPadding());
return i;
}
/**
* Adds a new CONSTANT_Utf8_info
* structure.
*
*