Mirror of the BLOAT repository
https://www.cs.purdue.edu/homes/hosking/bloat/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
459 lines
12 KiB
459 lines
12 KiB
/**
|
|
* All files in the distribution of BLOAT (Bytecode Level Optimization and
|
|
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
|
|
* Research Foundation of Purdue University. All rights reserved.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
package EDU.purdue.cs.bloat.editor;
|
|
|
|
import java.util.*;
|
|
|
|
import EDU.purdue.cs.bloat.reflect.*;
|
|
import EDU.purdue.cs.bloat.util.*;
|
|
|
|
/**
|
|
* ConstantPool models constants in the constant pool. Recall that the
|
|
* reflection mechanism represents constants as a tag and a value. ConstantPool
|
|
* consists of an array of <tt>reflect.Constant</tt>s that are resolved into
|
|
* their appropriate value (e.g. Type, NameAndType, MemberRef, etc.) as they are
|
|
* needed.
|
|
*
|
|
* @see EDU.purdue.cs.bloat.reflect.Constant
|
|
*
|
|
* @author Nate Nystrom (<a
|
|
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
|
|
*/
|
|
public class ConstantPool {
|
|
/**
|
|
* ConstantPool maintains some information about the constants in the
|
|
* constant pool to make its life easier.
|
|
*
|
|
* constantIndices A mapping between constants and their indices in the
|
|
* constant pool. Knowing this information makes adding constants to the
|
|
* constant pool easier.
|
|
*
|
|
* constants A list of the reflect.Constant objects that are used to create
|
|
* the ConstantPool.
|
|
*
|
|
* resolved A list of the constants in their resolved form (such as
|
|
* NameAndType or String)
|
|
*/
|
|
private Map constantIndices;
|
|
|
|
ResizeableArrayList constants;
|
|
|
|
ResizeableArrayList resolved;
|
|
|
|
/**
|
|
* Constructor. Resolve the constants in the constant pool, converting from
|
|
* the index-based representation of the class file to a more amenable
|
|
* external representation.
|
|
*
|
|
* @param c
|
|
* An array of Constant.
|
|
*/
|
|
public ConstantPool(final Constant[] c) {
|
|
constantIndices = new HashMap();
|
|
constants = new ResizeableArrayList(c.length);
|
|
resolved = new ResizeableArrayList(c.length);
|
|
|
|
/*
|
|
* constants = new ResizeableArrayList(c.length, 256); resolved = new
|
|
* ResizeableArrayList(c.length, 256);
|
|
*/
|
|
for (int i = 0; i < c.length; i++) {
|
|
constants.add(c[i]);
|
|
resolved.add(null);
|
|
if (c[i] != null) {
|
|
constantIndices.put(c[i], new Integer(i));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates a new, empty <code>ConstantPool</code>
|
|
*/
|
|
public ConstantPool() {
|
|
this.constantIndices = new HashMap();
|
|
this.constants = new ResizeableArrayList();
|
|
this.resolved = new ResizeableArrayList();
|
|
}
|
|
|
|
/**
|
|
* Obtain the resolved value of a constant at given index in the constant
|
|
* pool.
|
|
*
|
|
* @param idx
|
|
* Index into the constant pool.
|
|
* @return The value of the constant at index.
|
|
*/
|
|
public Object constantAt(final int idx) {
|
|
if (idx == 0) {
|
|
return null;
|
|
}
|
|
|
|
Object value = resolved.get(idx);
|
|
|
|
if (value != null) {
|
|
return value;
|
|
}
|
|
|
|
final Constant c = (Constant) constants.get(idx);
|
|
|
|
if (c == null) {
|
|
return null;
|
|
}
|
|
|
|
value = c.value();
|
|
|
|
if (value == null) {
|
|
return null;
|
|
}
|
|
|
|
// Okay, we have to resolve the Constant.
|
|
|
|
switch (c.tag()) {
|
|
case Constant.CLASS: {
|
|
// Lookup the UTF8 at the index and use the class name
|
|
// to create a Type.
|
|
Assert.isTrue(value instanceof Integer, "Invalid constant: " + c);
|
|
|
|
final int index = ((Integer) value).intValue();
|
|
Assert.isTrue(constantTag(index) == Constant.UTF8,
|
|
"Invalid constant: " + c);
|
|
|
|
final String className = (String) constantAt(index);
|
|
|
|
value = Type.getType(Type.classDescriptor(className));
|
|
break;
|
|
}
|
|
case Constant.STRING: {
|
|
// Lookup the UTF8 at the index and store the String directly.
|
|
Assert.isTrue(value instanceof Integer, "Invalid constant: " + c);
|
|
|
|
final int index = ((Integer) value).intValue();
|
|
Assert.isTrue(constantTag(index) == Constant.UTF8,
|
|
"Invalid constant: " + c);
|
|
|
|
value = constantAt(index);
|
|
break;
|
|
}
|
|
case Constant.FIELD_REF:
|
|
case Constant.METHOD_REF:
|
|
case Constant.INTERFACE_METHOD_REF: {
|
|
// The constant at the first index should be a CLASS.
|
|
//
|
|
// The constant at the second should be a NAME_AND_TYPE.
|
|
//
|
|
// Resolve the two constants and then create a MemberRef
|
|
// for this constant.
|
|
//
|
|
Assert.isTrue(value instanceof int[], "Invalid constant: " + c);
|
|
|
|
final int[] v = (int[]) value;
|
|
|
|
Assert.isTrue(constantTag(v[0]) == Constant.CLASS,
|
|
"Invalid constant: " + c);
|
|
Assert.isTrue(constantTag(v[1]) == Constant.NAME_AND_TYPE,
|
|
"Invalid constant: " + c);
|
|
|
|
final Type clazz = (Type) constantAt(v[0]);
|
|
final NameAndType nameAndType = (NameAndType) constantAt(v[1]);
|
|
|
|
value = new MemberRef(clazz, nameAndType);
|
|
break;
|
|
}
|
|
case Constant.NAME_AND_TYPE: {
|
|
// The constant at the first index should be a UTF8 with the
|
|
// name of the field.
|
|
//
|
|
// The constant at the second should be a UTF8 with the type
|
|
// of the field.
|
|
//
|
|
// Resolve the two constants as a String and a Type and then
|
|
// create a NameAndType for this constant.
|
|
//
|
|
Assert.isTrue(value instanceof int[], "Invalid constant: " + c);
|
|
|
|
final int[] v = (int[]) value;
|
|
|
|
Assert.isTrue(constantTag(v[0]) == Constant.UTF8,
|
|
"Invalid constant: " + c);
|
|
Assert.isTrue(constantTag(v[1]) == Constant.UTF8,
|
|
"Invalid constant: " + c);
|
|
|
|
final String name = (String) constantAt(v[0]);
|
|
final String type = (String) constantAt(v[1]);
|
|
|
|
value = new NameAndType(name, Type.getType(type));
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
resolved.ensureSize(idx + 1);
|
|
resolved.set(idx, value);
|
|
|
|
return value;
|
|
}
|
|
|
|
public int numConstants() {
|
|
return constants.size();
|
|
}
|
|
|
|
/**
|
|
* Get the tag of a constant.
|
|
*
|
|
* @param index
|
|
* Index into the constant pool.
|
|
* @return The tag of the constant at index, or Constant.UTF8.
|
|
*/
|
|
public int constantTag(final int index) {
|
|
if ((0 < index) && (index < constants.size())) {
|
|
final Constant c = (Constant) constants.get(index);
|
|
|
|
if (c != null) {
|
|
return c.tag();
|
|
}
|
|
}
|
|
|
|
return Constant.UTF8;
|
|
}
|
|
|
|
/**
|
|
* Get the index of the constant with the given tag and value.
|
|
*
|
|
* @param tag
|
|
* The constant's tag (for example, <tt>Constant.UTF8</tt>).
|
|
* @param value
|
|
* The constant's value (for example, a <tt>String</tt>).
|
|
* @return The index of the constant.
|
|
*/
|
|
public int constantIndex(final int tag, final Object value) {
|
|
return addConstant(tag, value);
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given class
|
|
*/
|
|
public int getClassIndex(final Class c) {
|
|
return (addConstant(Constant.CLASS, Type.getType(c)));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given integer
|
|
*/
|
|
public int getIntegerIndex(final Integer i) {
|
|
return (addConstant(Constant.INTEGER, i));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given float
|
|
*/
|
|
public int getFloatIndex(final Float f) {
|
|
return (addConstant(Constant.FLOAT, f));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given long
|
|
*/
|
|
public int getLongIndex(final Long l) {
|
|
return (addConstant(Constant.LONG, l));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given double
|
|
*/
|
|
public int getDoubleIndex(final Double d) {
|
|
return (addConstant(Constant.DOUBLE, d));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given class.
|
|
*/
|
|
public int getClassIndex(final Type type) {
|
|
Assert
|
|
.isTrue(type.isObject(), "Type " + type
|
|
+ " is not an class type");
|
|
// Make sure that the descriptor constant is also there
|
|
getTypeIndex(type);
|
|
return (addConstant(Constant.CLASS, type));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given
|
|
* <code>Type</code>
|
|
*/
|
|
public int getTypeIndex(final Type type) {
|
|
return (addConstant(Constant.UTF8, type.descriptor()));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given String
|
|
*/
|
|
public int getStringIndex(final String s) {
|
|
return (addConstant(Constant.STRING, s));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given
|
|
* <code>MemberRef</code>
|
|
*/
|
|
public int getMemberRefIndex(final MemberRef ref) {
|
|
return (addConstant(Constant.FIELD_REF, ref));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given
|
|
* <code>NameAndType</code>
|
|
*/
|
|
public int getNameAndTypeIndex(final NameAndType nat) {
|
|
return (addConstant(Constant.NAME_AND_TYPE, nat));
|
|
}
|
|
|
|
/**
|
|
* Returns the index of the constant pool entry for the given UTF8 string
|
|
*/
|
|
public int getUTF8Index(final String s) {
|
|
return (addConstant(Constant.UTF8, s));
|
|
}
|
|
|
|
/**
|
|
* Add a constant to the constant pool. Will not add the same constant
|
|
* twice.
|
|
*
|
|
* @param tag
|
|
* The constant's tag (for example, <tt>Constant.UTF8</tt>).
|
|
* @param value
|
|
* The constant's value (for example, a <tt>String</tt>).
|
|
* @return The index of the constant.
|
|
*/
|
|
public int addConstant(final int tag, final Object value) {
|
|
if (value == null) {
|
|
return 0;
|
|
}
|
|
|
|
Constant c;
|
|
|
|
switch (tag) {
|
|
case Constant.CLASS: {
|
|
Assert.isTrue(value instanceof Type, "Invalid value: " + value);
|
|
final int index = addConstant(Constant.UTF8, ((Type) value)
|
|
.className());
|
|
c = new Constant(Constant.CLASS, new Integer(index));
|
|
break;
|
|
}
|
|
case Constant.STRING: {
|
|
Assert.isTrue(value instanceof String, "Invalid value: " + value);
|
|
final int index = addConstant(Constant.UTF8, value);
|
|
c = new Constant(Constant.STRING, new Integer(index));
|
|
break;
|
|
}
|
|
case Constant.FIELD_REF:
|
|
case Constant.METHOD_REF:
|
|
case Constant.INTERFACE_METHOD_REF: {
|
|
// The constant at the first index should be a CLASS.
|
|
//
|
|
// The constant at the second should be a NAME_AND_TYPE.
|
|
//
|
|
// Resolve the two constants and then create a MemberRef
|
|
// for this constant.
|
|
//
|
|
Assert
|
|
.isTrue(value instanceof MemberRef, "Invalid value: "
|
|
+ value);
|
|
|
|
final int[] v = new int[2];
|
|
|
|
v[0] = addConstant(Constant.CLASS, ((MemberRef) value)
|
|
.declaringClass());
|
|
v[1] = addConstant(Constant.NAME_AND_TYPE, ((MemberRef) value)
|
|
.nameAndType());
|
|
|
|
c = new Constant(tag, v);
|
|
break;
|
|
}
|
|
case Constant.NAME_AND_TYPE: {
|
|
// The constant at the first index should be a UTF8 with the
|
|
// name of the field.
|
|
//
|
|
// The constant at the second should be a UTF8 with the type
|
|
// of the field.
|
|
//
|
|
// Resolve the two constants as a String and a Type and then
|
|
// create a NameAndType for this constant.
|
|
//
|
|
Assert.isTrue(value instanceof NameAndType, "Invalid value: "
|
|
+ value);
|
|
|
|
final int[] v = new int[2];
|
|
|
|
v[0] = addConstant(Constant.UTF8, ((NameAndType) value).name());
|
|
v[1] = addConstant(Constant.UTF8, ((NameAndType) value).type()
|
|
.descriptor());
|
|
|
|
c = new Constant(tag, v);
|
|
break;
|
|
}
|
|
case Constant.UTF8: {
|
|
final String s = (String) value;
|
|
c = new Constant(tag, s.intern());
|
|
break;
|
|
}
|
|
default: {
|
|
c = new Constant(tag, value);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Integer index = (Integer) constantIndices.get(c);
|
|
|
|
if (index == null) {
|
|
index = new Integer(constants.size());
|
|
constantIndices.put(c, index);
|
|
constants.add(c);
|
|
resolved.add(value);
|
|
|
|
if ((tag == Constant.LONG) || (tag == Constant.DOUBLE)) {
|
|
constants.add(null);
|
|
resolved.add(null);
|
|
}
|
|
}
|
|
|
|
return index.intValue();
|
|
}
|
|
|
|
/**
|
|
* Get an array of the constants in the pool.
|
|
*
|
|
* @return An array of the constants in the pool.
|
|
*/
|
|
public Constant[] constants() {
|
|
final Object[] a = constants.toArray();
|
|
final Constant[] array = new Constant[a.length];
|
|
System.arraycopy(a, 0, array, 0, a.length);
|
|
return array;
|
|
}
|
|
|
|
/**
|
|
* Returns an unmodifiable List of constants in this constant pool.
|
|
*/
|
|
public List getConstantsList() {
|
|
return Collections.unmodifiableList(this.constants);
|
|
}
|
|
}
|
|
|