package smart.updater;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.*;
import java.util.NoSuchElementException;
/**
* a class which searches through instruction lists, has a lot of overloaded methods
* it saves its current position, so multiple calls of its method find differant instructions
*
* for the methods which iterate (eg. nextFieldInstruction()), if they return dont find
* and return null, the current instruction will be at the first/last of the list, so more
* searching wont work, to save the current position, use getCurrentIndex()
* and setCurrentIndex(), or resetToStart() and resetToEnd()
*
* for methods which iterate (eg. nextFieldInstruction()), they start searching from the next
* instruction, not the current one. so if you're at a field instruction, nextFieldInstruction wont
* find it, but carry on.
*/
public class InstructionSearcher {
public static final byte MODE_START = 0x01;
public static final byte MODE_END = 0x02;
protected InstructionList list;
protected InstructionHandle current;
protected ConstantPoolGen theCPool;
/* Constructors */
/**
* @param mode Whether to have the current be the first, or last in the list
*/
public InstructionSearcher(InstructionList list, ConstantPoolGen theCPool, byte mode) {
if(list == null)
throw new IllegalArgumentException("list cant be null");
if(theCPool == null)
throw new IllegalArgumentException("theCPool cant be null");
if(mode != MODE_START && mode != MODE_END)
throw new IllegalArgumentException("mode has to be MODE_START or MODE_END");
current = (mode == MODE_START ? list.getStart() : list.getEnd());
this.list = list;
this.theCPool = theCPool;
}
public InstructionSearcher(InstructionList list, ConstantPoolGen theCPool) {
this(list, theCPool, MODE_START);
}
public InstructionSearcher(Method theMethod, String className, ConstantPoolGen theCPool, byte mode) {
this(new MethodGen(theMethod, className, theCPool).getInstructionList(), theCPool, mode);
}
public InstructionSearcher(Method theMethod, String className, ConstantPoolGen theCPool) {
this(theMethod, className, theCPool, MODE_START);
}
public InstructionSearcher(Method theMethod, ClassGen theClassGen, byte mode) {
this(theMethod, theClassGen.getClassName(), theClassGen.getConstantPool(), mode);
}
public InstructionSearcher(Method theMethod, ClassGen theClassGen) {
this(theMethod, theClassGen, MODE_START);
}
/* Little useful methods */
public InstructionList getList() { return list; }
public ConstantPoolGen getConstantPoolGen() { return theCPool; }
public String toString() {
return getClass().getName() + " index = " + getCurrentIndex() + " current = " + current.getPosition() + ": " + current().toString(theCPool.getConstantPool());
}
private boolean hasNext() {
return current != list.getEnd();
}
private boolean hasPrev() {
return current != list.getStart();
}
private void checkNext() {
if(!hasNext())
throw new NoSuchElementException("No more instructions in " + this);
}
private void checkPrev() {
if(!hasPrev())
throw new NoSuchElementException("No more instructions in " + this);
}
/* set/get methods */
/**
* sets a new current, must be contained in the InstructionList
*/
public void setCurrent(InstructionHandle handle) {
if(!list.contains(handle))
throw new IllegalArgumentException("handle not contained in list");
current = handle;
}
/**
* throws ArrayIndexOutOfBoundsException if needed
*/
public void setCurrentIndex(int index) {
setCurrent(list.getInstructionHandles()[index]);
}
/**
* gets the index of the current instruction
* uses a linear search
*/
public int getCurrentIndex() {
InstructionHandle c = list.getStart();
for(int f = 0;; f++, c = c.getNext()) {
if(c == current)
return f;
else
if(c == list.getEnd())
break;
}
throw new IndexOutOfBoundsException("current handle is not contained in list!");
//should be not possible
}
public void resetToStart() {
current = list.getStart();
}
public void resetToEnd() {
current = list.getEnd();
}
public Instruction current() {
return current.getInstruction();
}
public Instruction next() {
checkNext();
current = current.getNext();
return current.getInstruction();
}
public Instruction prev() {
checkPrev();
current = current.getPrev();
return current.getInstruction();
}
public Instruction next(int hopCount) {
for(int f = 1; f < hopCount; f++)
next();
return next();
}
public Instruction prev(int hopCount) {
for(int f = 1; f < hopCount; f++)
prev();
return prev();
}
/* Searching methods */
/**
* Is passed to methods nextConstraint and prevConstraint.
*/
public static interface Constraint {
boolean matches(InstructionHandle current, ConstantPoolGen theCPool);
}
public Instruction nextConstraint(Constraint con) {
while(hasNext()) {
current = current.getNext();
if(con.matches(current, theCPool))
return current.getInstruction();
}
return null;
}
public Instruction prevConstraint(Constraint con) {
while(hasPrev()) {
current = current.getPrev();
if(con.matches(current, theCPool))
return current.getInstruction();
}
return null;
}
/**
* starts at the beginning and searchs the entire InstructionList for
* the Constraint, returns its index or -1 if not found
*/
public int containsConstraint(Constraint con) {
InstructionHandle c = list.getStart();
for(int f = 0;;f++, c = c.getNext()) {
if(con.matches(c, theCPool))
return f;
if(c == list.getEnd())
break;
}
return -1;
}
/**
* iterates until it finds the next instruction which is an instance of the param
* or null if not found
* note: it is not Class<? extends Instruction> to allow for searching for
* interfaces such as ConstantPushInstruction
* @param instructionClass The class to check instance for
*/
public Instruction nextOfType(Class<?> instructionClass) {
//TODO try using generic methods here, it might work
while(hasNext()) {
Instruction i = next();
if(instructionClass.isInstance(i))
return i;
}
return null;
}
/**
* iterates until it finds the prev instruction which is an instance of the param
* or null if not found
* note: it is not Class<? extends Instruction> to allow for searching for
* interfaces such as ConstantPushInstruction
* @param instructionClass The class to check instance for
*/
public Instruction prevOfType(Class<?> instructionClass) {
while(hasPrev()) {
Instruction i = prev();
if(instructionClass.isInstance(i))
return i;
}
return null;
}
/**
* iterates until it finds the next fieldinstruction which points to the
* constant pool index parameter
*/
public FieldInstruction nextFieldInstruction(int cpIndex) {
while(hasNext()) {
Instruction i = next();
if(i instanceof FieldInstruction && ((FieldInstruction)i).getIndex() == cpIndex)
return (FieldInstruction)i;
}
return null;
}
/**
* iterates until it finds the prev fieldinstruction which points to the
* constant pool index parameter
*/
public FieldInstruction prevFieldInstruction(int cpIndex) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof FieldInstruction && ((FieldInstruction)i).getIndex() == cpIndex)
return (FieldInstruction)i;
}
return null;
}
public FieldInstruction nextFieldInstruction() {
while(hasNext()) {
Instruction i = next();
if(i instanceof FieldInstruction)
return (FieldInstruction)i;
}
return null;
}
public FieldInstruction prevFieldInstruction() {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof FieldInstruction)
return (FieldInstruction)i;
}
return null;
}
public FieldInstruction nextFieldInstructionOf(String fieldPath) {
while(hasNext()) {
Instruction i = next();
if(i instanceof FieldInstruction)
{
String f = ((FieldInstruction) i).getClassName(theCPool)+'.'+((FieldInstruction) i).getFieldName(theCPool);
if(f.equals(fieldPath))
return (FieldInstruction)i;
}
}
return null;
}
public FieldInstruction prevFieldInstructionOf(String fieldPath) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof FieldInstruction)
{
String f = ((FieldInstruction) i).getClassName(theCPool)+'.'+((FieldInstruction) i).getFieldName(theCPool);
if(f.equals(fieldPath))
return (FieldInstruction)i;
}
}
return null;
}
/**
* iterates until it finds the next fieldinstruction which has the classname,
* fieldname and signature of the parameters, if the constant pool fieldref of those
* parameters does not exist, null is returned
*/
public FieldInstruction nextFieldInstruction(String class_name, String field_name, String signature) {
int index = theCPool.lookupFieldref(class_name, field_name, signature);
if(index == -1)
return null;
return nextFieldInstruction(index);
}
/**
* iterates until it finds the prev fieldinstruction which has the classname,
* fieldname and signature of the parameters, if the constant pool fieldref of those
* parameters does not exist, null is returned
*/
public FieldInstruction prevFieldInstruction(String class_name, String field_name, String signature) {
int index = theCPool.lookupFieldref(class_name, field_name, signature);
if(index == -1)
return null;
return prevFieldInstruction(index);
}
/**
* iterates until it finds the next fieldinstruction which has the type signature,
* of the parameter
*/
public FieldInstruction nextFieldInstruction(String typeSignature) {
while(hasNext()) {
Instruction i = next();
if(i instanceof FieldInstruction && ((FieldInstruction)i).getType(theCPool).getSignature().equals(typeSignature))
return (FieldInstruction)i;
}
return null;
}
/**
* iterates until it finds the prev fieldinstruction which has the type signature,
* of the parameter
*/
public FieldInstruction prevFieldInstruction(String typeSignature) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof FieldInstruction && ((FieldInstruction)i).getType(theCPool).getSignature().equals(typeSignature))
return (FieldInstruction)i;
}
return null;
}
public FieldInstruction nextFieldInstruction(Type type) {
return nextFieldInstruction(type.getSignature());
}
public FieldInstruction prevFieldInstruction(Type type) {
return prevFieldInstruction(type.getSignature());
}
/**
* iterates until it finds the next invokeinstruction which points to the
* constant pool index parameter
* note: this family of method doesnt have nextInvokeInstruction(ClassName, MethodName, Signature)
* because INVOKEINTERFACE works slightly differantly, its better the user just does a lookupMethodref
*/
public InvokeInstruction nextInvokeInstruction(int cpIndex) {
while(hasNext()) {
Instruction i = next();
if(i instanceof InvokeInstruction && ((InvokeInstruction)i).getIndex() == cpIndex)
return (InvokeInstruction)i;
}
return null;
}
public InvokeInstruction prevInvokeInstruction(int cpIndex) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof InvokeInstruction && ((InvokeInstruction)i).getIndex() == cpIndex)
return (InvokeInstruction)i;
}
return null;
}
public InvokeInstruction nextInvokeInstruction(Type returnType) {
while(hasNext()) {
Instruction i = next();
if(i instanceof InvokeInstruction && ((InvokeInstruction)i).getReturnType(theCPool).equals(returnType))
return (InvokeInstruction)i;
}
return null;
}
public InvokeInstruction prevInvokeInstruction(Type returnType) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof InvokeInstruction && ((InvokeInstruction)i).getReturnType(theCPool).equals(returnType))
return (InvokeInstruction)i;
}
return null;
}
public ConstantPushInstruction nextConstantPushInstruction(Number value) {
while(hasNext()) {
Instruction i = next();
if(i instanceof ConstantPushInstruction && ((ConstantPushInstruction)i).getValue().equals(value))
return (ConstantPushInstruction)i;
}
return null;
}
public ConstantPushInstruction prevConstantPushInstruction(Number value) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof ConstantPushInstruction && ((ConstantPushInstruction)i).getValue().equals(value))
return (ConstantPushInstruction)i;
}
return null;
}
/**
* finds the next LDC which has the value
* it can be of type String, Integer, Float ect..
*/
public LDC nextLDC(Object value) {
while(hasNext()) {
Instruction i = next();
if(i instanceof LDC && ((LDC)i).getValue(theCPool).equals(value))
return (LDC)i;
}
return null;
}
public LDC prevLDC(Object value) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof LDC && ((LDC)i).getValue(theCPool).equals(value))
return (LDC)i;
}
return null;
}
public Instruction nextGETSTATIC() {
while(hasNext()) {
Instruction i = next();
if(i instanceof GETSTATIC)
return (GETSTATIC)i;
}
return null;
}
public Instruction prevGETSTATIC() {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof GETSTATIC)
return (GETSTATIC)i;
}
return null;
}
public Instruction nextGETFIELD() {
while(hasNext()) {
Instruction i = next();
if(i instanceof GETFIELD)
return (GETFIELD)i;
}
return null;
}
public Instruction prevGETFIELD() {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof GETFIELD)
return (GETFIELD)i;
}
return null;
}
public Instruction nextPUTFIELD() {
while(hasNext()) {
Instruction i = next();
if(i instanceof PUTFIELD)
return (PUTFIELD)i;
}
return null;
}
public Instruction prevPUTFIELD() {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof PUTFIELD)
return (PUTFIELD)i;
}
return null;
}
public Instruction nextGETFIELD(String path) {
while(hasNext()) {
Instruction i = next();
if(i instanceof GETFIELD)
{
String fpath = ((GETFIELD) i).getClassName(theCPool)+'.'+((GETFIELD) i).getFieldName(theCPool);
if(fpath.equals(path))
return (GETFIELD)i;
}
}
return null;
}
public Instruction prevGETFIELD(String path) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof GETFIELD)
{
String fpath = ((GETFIELD) i).getClassName(theCPool)+'.'+((GETFIELD) i).getFieldName(theCPool);
if(fpath.equals(path))
return (GETFIELD)i;
}
}
return null;
}
public Instruction nextNEW() {
while(hasNext()) {
Instruction i = next();
if(i instanceof NEW)
return (NEW)i;
}
return null;
}
public Instruction prevNEW() {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof NEW)
return (NEW)i;
}
return null;
}
public Instruction nextALOAD(int index) {
while(hasNext()) {
Instruction i = next();
if(i instanceof ALOAD)
if(((ALOAD)i).getIndex() == index)
return (ALOAD)i;
}
return null;
}
public Instruction prevALOAD(int index) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof ALOAD)
if(((ALOAD)i).getIndex() == index)
return (ALOAD)i;
}
return null;
}
public CPInstruction nextCPInstruction(int index) {
while(hasNext()) {
Instruction i = next();
if(i instanceof CPInstruction && ((CPInstruction)i).getIndex() == index)
return (CPInstruction)i;
}
return null;
}
public CPInstruction prevCPInstruction(int index) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof CPInstruction && ((CPInstruction)i).getIndex() == index)
return (CPInstruction)i;
}
return null;
}
public LocalVariableInstruction nextLocalVariableInstruction(int index) {
while(hasNext()) {
Instruction i = next();
if(i instanceof LocalVariableInstruction && ((LocalVariableInstruction)i).getIndex() == index)
return (LocalVariableInstruction)i;
}
return null;
}
public LocalVariableInstruction prevLocalVariableInstruction(int index) {
while(hasPrev()) {
Instruction i = prev();
if(i instanceof LocalVariableInstruction && ((LocalVariableInstruction)i).getIndex() == index)
return (LocalVariableInstruction)i;
}
return null;
}
}