Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package serp.bytecode.lowlevel;
import java.io.*;
import java.util.*;
import serp.bytecode.visitor.*;
import serp.util.*;
/**
* A bytecode constant pool, containing entries for all strings,
* constants, classes, etc referenced in the class structure and method
* opcodes. In keeping with the low-level bytecode representation, all pool
* indexes are 1-based and {@link LongEntry}s and {@link DoubleEntry}s each
* occupy two indexes in the pool.
*
* @author Abe White
*/
public class ConstantPool implements VisitAcceptor {
private List _entries = new ArrayList(50);
private Map _lookup = new HashMap(50);
/**
* Default constructor.
*/
public ConstantPool() {
}
/**
* Return all the entries in the pool.
*/
public Entry[] getEntries() {
List entries = new ArrayList(_entries.size());
Entry entry;
for (Iterator itr = _entries.iterator(); itr.hasNext();) {
entry = (Entry) itr.next();
if (entry != null)
entries.add(entry);
}
return (Entry[]) entries.toArray(new Entry[entries.size()]);
}
/**
* Retrieve the entry at the specified 1-based index.
*
* @throws IndexOutOfBoundsException if index is invalid,
* including the case that it points to the second slot of a
* long or double entry
*/
public Entry getEntry(int index) {
Entry entry = (Entry) _entries.get(index - 1);
if (entry == null)
throw new IndexOutOfBoundsException("index = " + index);
return entry;
}
/**
* Return the index of the given entry, or 0 if it is not in the pool.
*/
public int indexOf(Entry entry) {
if (entry == null || entry.getPool() != this)
return 0;
return entry.getIndex();
}
/**
* Add an entry to the pool.
*
* @return the index at which the entry was added
*/
public int addEntry(Entry entry) {
if (entry.getPool() != this)
addEntry(getKey(entry), entry);
return entry.getIndex();
}
/**
* Add an entry to the pool using the given key.
*/
private int addEntry(Object key, Entry entry) {
entry.setPool(this);
_entries.add(entry);
entry.setIndex(_entries.size());
_lookup.put(key, entry);
if (entry.isWide())
_entries.add(null);
return entry.getIndex();
}
/**
* Remove the given entry from the pool.
*
* @return false if the entry is not in the pool, true otherwise
*/
public boolean removeEntry(Entry entry) {
if (entry == null || entry.getPool() != this)
return false;
int index = entry.getIndex() - 1;
entry.setPool(null);
entry.setIndex(0);
_entries.remove(index);
if (entry.isWide())
_entries.remove(index);
_lookup.remove(getKey(entry));
// rehash all the entries after the removed one with their new index
Object key;
for (int i = index; i < _entries.size(); i++) {
entry = (Entry) _entries.get(i);
if (entry != null) {
key = getKey(entry);
_lookup.remove(key);
entry.setIndex(i + 1);
_lookup.put(key, entry);
}
}
return true;
}
/**
* Clear all entries from the pool.
*/
public void clear() {
Entry entry;
for (Iterator itr = _entries.iterator(); itr.hasNext();) {
entry = (Entry) itr.next();
if (entry != null) {
entry.setPool(null);
entry.setIndex(0);
}
}
_entries.clear();
_lookup.clear();
}
/**
* Return the number of places occupied in the pool, including the fact
* that long and double entries occupy two places.
*/
public int size() {
return _entries.size();
}
/**
* Return the index of the {@link UTF8Entry} with the given value, or
* 0 if it does not exist.
*
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findUTF8Entry(String value, boolean add) {
if (value == null) {
if (add)
throw new NullPointerException("value = null");
return 0;
}
int index = find(value);
if (!add || index > 0)
return index;
return addEntry(value, new UTF8Entry(value));
}
/**
* Return the constant pool index of the {@link DoubleEntry} for the given
* value, or 0 if it does not exist.
*
* @param value the value to find
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findDoubleEntry(double value, boolean add) {
Double key = new Double(value);
int index = find(key);
if (!add || (index > 0))
return index;
return addEntry(key, new DoubleEntry(value));
}
/**
* Return the constant pool index of the {@link FloatEntry} for the given
* value, or 0 if it does not exist.
*
* @param value the value to find
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findFloatEntry(float value, boolean add) {
Float key = new Float(value);
int index = find(key);
if (!add || index > 0)
return index;
return addEntry(key, new FloatEntry(value));
}
/**
* Return the constant pool index of the {@link IntEntry} for the given
* value, or 0 if it does not exist.
*
* @param value the value to find
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findIntEntry(int value, boolean add) {
Integer key = Numbers.valueOf(value);
int index = find(key);
if (!add || index > 0)
return index;
return addEntry(key, new IntEntry(value));
}
/**
* Return the constant pool index of the {@link LongEntry} for the given
* value, or 0 if it does not exist.
*
* @param value the value to find
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findLongEntry(long value, boolean add) {
Long key = Numbers.valueOf(value);
int index = find(key);
if (!add || index > 0)
return index;
return addEntry(key, new LongEntry(value));
}
/**
* Return the constant pool index of the {@link StringEntry} for the given
* string value, or 0 if it does not exist.
*
* @param value the value to find
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findStringEntry(String value, boolean add) {
int valueIndex = findUTF8Entry(value, add);
if (valueIndex == 0)
return 0;
StringKey key = new StringKey(valueIndex);
int index = find(key);
if (!add || index > 0)
return index;
return addEntry(key, new StringEntry(valueIndex));
}
/**
* Return the constant pool index of the {@link ClassEntry} for the given
* class name, or 0 if it does not exist.
*
* @param name the class name in internal form
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findClassEntry(String name, boolean add) {
int nameIndex = findUTF8Entry(name, add);
if (nameIndex == 0)
return 0;
ClassKey key = new ClassKey(nameIndex);
int index = find(key);
if (!add || index > 0)
return index;
return addEntry(key, new ClassEntry(nameIndex));
}
/**
* Return the constant pool index of the {@link NameAndTypeEntry} for the
* given name and descriptor, or 0 if it does not exist.
*
* @param name the name of the entity
* @param desc the descriptor of the entity in internal form
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findNameAndTypeEntry(String name, String desc, boolean add) {
int nameIndex = findUTF8Entry(name, add);
if (nameIndex == 0)
return 0;
int descIndex = findUTF8Entry(desc, add);
if (descIndex == 0)
return 0;
NameAndTypeKey key = new NameAndTypeKey(nameIndex, descIndex);
int index = find(key);
if (!add || index > 0)
return index;
return addEntry(key, new NameAndTypeEntry(nameIndex, descIndex));
}
/**
* Return the constant pool index of the {@link FieldEntry} for the
* given name, descriptor, and owner class name.
*
* @param owner the name of the field's owning class in internal form
* @param name the name of the field
* @param desc the descriptor of the field in internal form
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findFieldEntry(String owner, String name, String desc,
boolean add) {
return findComplexEntry(owner, name, desc, Entry.FIELD, add);
}
/**
* Return the constant pool index of the {@link MethodEntry} for the
* given name, descriptor, and owner class name.
*
* @param owner the name of the method's owning class in internal form
* @param name the name of the method
* @param desc the descriptor of the method in internal form
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findMethodEntry(String owner, String name, String desc,
boolean add) {
return findComplexEntry(owner, name, desc, Entry.METHOD, add);
}
/**
* Return the constant pool index of the {@link InterfaceMethodEntry} for
* the given name, descriptor, and owner class name.
*
* @param owner the name of the method's owning class in internal form
* @param name the name of the method
* @param desc the descriptor of the method in internal form
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
public int findInterfaceMethodEntry(String owner, String name, String desc,
boolean add) {
return findComplexEntry(owner, name, desc, Entry.INTERFACEMETHOD, add);
}
public int findInvokeDynamicEntry(int bootstrapMethodIndex, String name, String desc, boolean add) {
int descIndex = findNameAndTypeEntry(name, desc, add);
if (descIndex == 0)
return 0;
Object key = new InvokeDynamicKey(bootstrapMethodIndex, descIndex);
int index = find(key);
if (!add || index > 0)
return index;
Entry entry = new InvokeDynamicEntry(bootstrapMethodIndex, descIndex);
return addEntry(key, entry);
}
/**
* Return the constant pool index of the {@link ComplexEntry} for the
* given name, descriptor, and owner class name.
*
* @param owner the name of the owning class in internal form
* @param name the name of the entity
* @param desc the descriptor of the entity in internal form
* @param type the type of entry: field, method, interface method
* @param add if true, the entry will be added if it does not
* already exist, and the new entry's index returned
*/
private int findComplexEntry(String owner, String name, String desc,
int type, boolean add) {
int classIndex = findClassEntry(owner, add);
if (classIndex == 0)
return 0;
int descIndex = findNameAndTypeEntry(name, desc, add);
if (descIndex == 0)
return 0;
Object key = null;
switch (type) {
case Entry.FIELD:
key = new FieldKey(classIndex, descIndex);
break;
case Entry.METHOD:
key = new MethodKey(classIndex, descIndex);
break;
case Entry.INTERFACEMETHOD:
key = new InterfaceMethodKey(classIndex, descIndex);
break;
}
int index = find(key);
if (!add || index > 0)
return index;
Entry entry = null;
switch (type) {
case Entry.FIELD:
entry = new FieldEntry(classIndex, descIndex);
break;
case Entry.METHOD:
entry = new MethodEntry(classIndex, descIndex);
break;
case Entry.INTERFACEMETHOD:
entry = new InterfaceMethodEntry(classIndex, descIndex);
break;
}
return addEntry(key, entry);
}
public void acceptVisit(BCVisitor visit) {
visit.enterConstantPool(this);
Entry entry;
for (Iterator itr = _entries.iterator(); itr.hasNext();) {
entry = (Entry) itr.next();
if (entry == null)
continue;
visit.enterEntry(entry);
entry.acceptVisit(visit);
visit.exitEntry(entry);
}
visit.exitConstantPool(this);
}
/**
* Fill the constant pool from the given bytecode stream.
*/
public void read(DataInput in) throws IOException {
clear();
int entryCount = in.readUnsignedShort();
Entry entry;
for (int i = 1; i < entryCount; i++) {
entry = Entry.read(in);
addEntry(entry);
if (entry.isWide())
i++;
}
}
/**
* Write the constant pool to the given bytecode stream.
*/
public void write(DataOutput out) throws IOException {
out.writeShort(_entries.size() + 1);
Entry entry;
for (Iterator itr = _entries.iterator(); itr.hasNext();) {
entry = (Entry) itr.next();
if (entry != null)
Entry.write(entry, out);
}
}
/**
* Called by constant pool entries when they are mutated.
*/
void modifyEntry(Object origKey, Entry entry) {
_lookup.remove(origKey);
_lookup.put(getKey(entry), entry);
}
/**
* Returns the constant pool index of the entry with the given key.
*/
private int find(Object key) {
Entry entry = (Entry) _lookup.get(key);
if (entry == null)
return 0;
return entry.getIndex();
}
/**
* Return the hash key used for the specified entry.
*/
static Object getKey(Entry entry) {
switch (entry.getType()) {
case Entry.CLASS:
return new ClassKey(((ClassEntry) entry).getNameIndex());
case Entry.FIELD:
FieldEntry fe = (FieldEntry) entry;
return new FieldKey(fe.getClassIndex(), fe.getNameAndTypeIndex());
case Entry.METHOD:
MethodEntry me = (MethodEntry) entry;
return new MethodKey(me.getClassIndex(), me.getNameAndTypeIndex());
case Entry.INTERFACEMETHOD:
InterfaceMethodEntry ime = (InterfaceMethodEntry) entry;
return new InterfaceMethodKey(ime.getClassIndex(),
ime.getNameAndTypeIndex());
case Entry.INVOKEDYNAMIC:
InvokeDynamicEntry ide = (InvokeDynamicEntry) entry;
return new InvokeDynamicKey(ide.getBootstrapMethodAttrIndex(), ide.getNameAndTypeIndex());
case Entry.STRING:
return new StringKey(((StringEntry) entry).getStringIndex());
case Entry.INT:
case Entry.FLOAT:
case Entry.LONG:
case Entry.DOUBLE:
case Entry.UTF8:
return ((ConstantEntry) entry).getConstant();
case Entry.NAMEANDTYPE:
NameAndTypeEntry nte = (NameAndTypeEntry) entry;
return new NameAndTypeKey(nte.getNameIndex(),
nte.getDescriptorIndex());
default:
return null;
}
}
/**
* Base class key for entries with one ptr to another entry.
*/
private static abstract class PtrKey {
private final int _index;
public PtrKey(int index) {
_index = index;
}
public int hashCode() {
return _index;
}
public boolean equals(Object other) {
if (other == this)
return true;
if (other.getClass() != getClass())
return false;
return ((PtrKey) other)._index == _index;
}
}
/**
* Key for string entries.
*/
private static class StringKey extends PtrKey {
public StringKey(int index) {
super(index);
}
}
/**
* Key for class entries.
*/
private static class ClassKey extends PtrKey {
public ClassKey(int index) {
super(index);
}
}
/**
* Base class key for entries with two ptr to other entries.
*/
private static abstract class DoublePtrKey {
private final int _index1;
private final int _index2;
public DoublePtrKey(int index1, int index2) {
_index1 = index1;
_index2 = index2;
}
public int hashCode() {
return _index1 ^ _index2;
}
public boolean equals(Object other) {
if (other == this)
return true;
if (other.getClass() != getClass())
return false;
DoublePtrKey key = (DoublePtrKey) other;
return key._index1 == _index1 && key._index2 == _index2;
}
}
/**
* Key for name and type entries.
*/
private static class NameAndTypeKey extends DoublePtrKey {
public NameAndTypeKey(int index1, int index2) {
super(index1, index2);
}
}
/**
* Key for field entries.
*/
private static class FieldKey extends DoublePtrKey {
public FieldKey(int index1, int index2) {
super(index1, index2);
}
}
/**
* Key for method entries.
*/
private static class MethodKey extends DoublePtrKey {
public MethodKey(int index1, int index2) {
super(index1, index2);
}
}
/**
* Key for interface method entries.
*/
private static class InterfaceMethodKey extends DoublePtrKey {
public InterfaceMethodKey(int index1, int index2) {
super(index1, index2);
}
}
/**
* Key for method entries.
*/
private static class InvokeDynamicKey extends DoublePtrKey {
public InvokeDynamicKey(int index1, int index2) {
super(index1, index2);
}
}
}