1 package serp.bytecode; 2 3 import java.io.*; 4 import java.util.*; 5 6 import serp.bytecode.visitor.*; 7 8 /*** 9 * An instruction that specifies a position in the code block to jump to. 10 * Examples include <code>go2, jsr</code>, etc. 11 * 12 * @author Abe White 13 */ 14 public abstract class JumpInstruction extends Instruction 15 implements InstructionPtr { 16 private InstructionPtrStrategy _target = new InstructionPtrStrategy(this); 17 18 JumpInstruction(Code owner, int opcode) { 19 super(owner, opcode); 20 } 21 22 /*** 23 * Get the current target instruction to jump to, if it has been set. 24 */ 25 public Instruction getTarget() { 26 return _target.getTargetInstruction(); 27 } 28 29 /*** 30 * Set the instruction to jump to; the instruction must already be 31 * added to the code block. 32 * 33 * @return this instruction, for method chaining 34 */ 35 public JumpInstruction setTarget(Instruction instruction) { 36 _target.setTargetInstruction(instruction); 37 return this; 38 } 39 40 /*** 41 * JumpInstructions are equal if they represent the same operation and 42 * the instruction they jump to is the 43 * same, or if the jump Instruction of either is unset. 44 */ 45 public boolean equalsInstruction(Instruction other) { 46 if (this == other) 47 return true; 48 if (!super.equalsInstruction(other)) 49 return false; 50 51 Instruction target = ((JumpInstruction) other).getTarget(); 52 return target == null || getTarget() == null || target == getTarget(); 53 } 54 55 public void updateTargets() { 56 _target.updateTargets(); 57 } 58 59 public void replaceTarget(Instruction oldTarget, Instruction newTarget) { 60 _target.replaceTarget(oldTarget, newTarget); 61 } 62 63 public void acceptVisit(BCVisitor visit) { 64 visit.enterJumpInstruction(this); 65 visit.exitJumpInstruction(this); 66 } 67 68 void read(Instruction orig) { 69 super.read(orig); 70 _target.setByteIndex(((JumpInstruction) orig)._target.getByteIndex()); 71 } 72 73 void read(DataInput in) throws IOException { 74 super.read(in); 75 switch (getOpcode()) { 76 case Constants.GOTOW: 77 case Constants.JSRW: 78 _target.setByteIndex(getByteIndex() + in.readInt()); 79 break; 80 default: 81 _target.setByteIndex(getByteIndex() + in.readShort()); 82 } 83 } 84 85 void write(DataOutput out) throws IOException { 86 super.write(out); 87 switch (getOpcode()) { 88 case Constants.GOTOW: 89 case Constants.JSRW: 90 out.writeInt(_target.getByteIndex() - getByteIndex()); 91 break; 92 default: 93 out.writeShort(_target.getByteIndex() - getByteIndex()); 94 } 95 } 96 97 public void setOffset(int offset) { 98 _target.setByteIndex(getByteIndex() + offset); 99 } 100 101 public int getOffset() { 102 return _target.getByteIndex() - getByteIndex(); 103 } 104 }