serp.bytecode.LookupSwitchInstruction Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of serp Show documentation
Show all versions of serp Show documentation
Serp is an open source framework for manipulating Java bytecode.
The newest version!
package serp.bytecode;
import java.io.*;
import java.util.*;
import serp.bytecode.visitor.*;
import serp.util.*;
/**
* The lookupswitch
instruction.
*
* @author Abe White
*/
public class LookupSwitchInstruction extends JumpInstruction {
// case info
private List _matches = new LinkedList();
private List _cases = new LinkedList();
LookupSwitchInstruction(Code owner) {
super(owner, Constants.LOOKUPSWITCH);
}
int getLength() {
// don't call super.getLength(), cause JumpInstruction will return
// value assuming this is an 'if' or 'goto' instruction
int length = 1;
// make the first byte of the 'default' a multiple of 4 from the
// start of the method
int byteIndex = getByteIndex() + 1;
for (; (byteIndex % 4) != 0; byteIndex++, length++);
// default, npairs
length += 8;
// pairs
length += (8 * _matches.size());
return length;
}
public int getStackChange() {
return -1;
}
/**
* Synonymous with {@link #getTarget}.
*/
public Instruction getDefaultTarget() {
return getTarget();
}
/**
* Synonymous with {@link #setTarget}.
*/
public LookupSwitchInstruction setDefaultTarget(Instruction ins) {
return (LookupSwitchInstruction) setTarget(ins);
}
/**
* Synonymous with {@link #getOffset}.
*/
public int getDefaultOffset() {
return getOffset();
}
/**
* Synonymous with {@link #setOffset}.
*/
public LookupSwitchInstruction setDefaultOffset(int offset) {
setOffset(offset);
return this;
}
/**
* Set the match-jumppt pairs for this switch.
*
* @return this instruction, for method chaining
*/
public LookupSwitchInstruction setCases(int[] matches,
Instruction[] targets) {
_matches.clear();
_cases.clear();
for (int i = 0; i < matches.length; i++)
_matches.add(Numbers.valueOf(matches[i]));
for (int i = 0; i < targets.length; i++) {
InstructionPtrStrategy next = new InstructionPtrStrategy(this);
next.setTargetInstruction(targets[i]);
_cases.add(next);
}
invalidateByteIndexes();
return this;
}
public int[] getOffsets() {
int bi = getByteIndex();
int[] offsets = new int[_cases.size()];
for (int i = 0; i < offsets.length; i++)
offsets[i] = ((InstructionPtrStrategy) _cases.get(i)).getByteIndex()
- bi;
return offsets;
}
/**
* Return the values of the case statements for this switch.
*/
public int[] getMatches() {
int[] matches = new int[_matches.size()];
Iterator itr = _matches.iterator();
for (int i = 0; i < matches.length; i++)
matches[i] = ((Integer) itr.next()).intValue();
return matches;
}
/**
* Return the targets of the case statements for this switch.
*/
public Instruction[] getTargets() {
Instruction[] result = new Instruction[_cases.size()];
for (int i = 0; i < result.length; i++)
result[i] = ((InstructionPtrStrategy) _cases.get(i)).
getTargetInstruction();
return result;
}
/**
* Add a case to this switch.
*
* @return this instruction, for method chaining
*/
public LookupSwitchInstruction addCase(int match, Instruction target) {
_matches.add(Numbers.valueOf(match));
_cases.add(new InstructionPtrStrategy(this, target));
invalidateByteIndexes();
return this;
}
private Instruction findJumpPoint(int jumpByteIndex, List inss) {
Instruction ins;
for (Iterator itr = inss.iterator(); itr.hasNext();) {
ins = (Instruction) itr.next();
if (ins.getByteIndex() == jumpByteIndex)
return ins;
}
return null;
}
public void updateTargets() {
super.updateTargets();
for (Iterator itr = _cases.iterator(); itr.hasNext();)
((InstructionPtrStrategy) itr.next()).updateTargets();
}
public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
super.replaceTarget(oldTarget, newTarget);
for (Iterator itr = _cases.iterator(); itr.hasNext();)
((InstructionPtrStrategy) itr.next()).replaceTarget(oldTarget,
newTarget);
}
public void acceptVisit(BCVisitor visit) {
visit.enterLookupSwitchInstruction(this);
visit.exitLookupSwitchInstruction(this);
}
void read(Instruction orig) {
super.read(orig);
LookupSwitchInstruction ins = (LookupSwitchInstruction) orig;
_matches = new LinkedList(ins._matches);
_cases.clear();
for (Iterator itr = ins._cases.iterator(); itr.hasNext();) {
InstructionPtrStrategy origPtr = (InstructionPtrStrategy)itr.next();
InstructionPtrStrategy newPtr = new InstructionPtrStrategy(this);
newPtr.setByteIndex(origPtr.getByteIndex());
_cases.add(newPtr);
}
invalidateByteIndexes();
}
void read(DataInput in) throws IOException {
// don't call super
int bi = getByteIndex();
for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++)
in.readByte();
setOffset(in.readInt());
_matches.clear();
_cases.clear();
for (int i = 0, pairCount = in.readInt(); i < pairCount; i++) {
_matches.add(Numbers.valueOf(in.readInt()));
InstructionPtrStrategy next = new InstructionPtrStrategy(this);
next.setByteIndex(bi + in.readInt());
_cases.add(next);
}
}
void write(DataOutput out) throws IOException {
// don't call super
int bi = getByteIndex();
for (int byteIndex = bi + 1; (byteIndex % 4) != 0; byteIndex++)
out.writeByte(0);
out.writeInt(getOffset());
out.writeInt(_matches.size());
for (int i = 0; i < _matches.size(); i++) {
out.writeInt(((Integer) _matches.get(i)).intValue());
out.writeInt(((InstructionPtrStrategy) _cases.get(i)).getByteIndex()
- bi);
}
}
}