001 package serp.bytecode;
002
003 import java.io.*;
004 import java.util.*;
005
006 import serp.bytecode.visitor.*;
007
008 /**
009 * An instruction that specifies a position in the code block to jump to.
010 * Examples include <code>go2, jsr</code>, etc.
011 *
012 * @author Abe White
013 */
014 public abstract class JumpInstruction extends Instruction
015 implements InstructionPtr {
016 private InstructionPtrStrategy _target = new InstructionPtrStrategy(this);
017
018 JumpInstruction(Code owner, int opcode) {
019 super(owner, opcode);
020 }
021
022 /**
023 * Get the current target instruction to jump to, if it has been set.
024 */
025 public Instruction getTarget() {
026 return _target.getTargetInstruction();
027 }
028
029 /**
030 * Set the instruction to jump to; the instruction must already be
031 * added to the code block.
032 *
033 * @return this instruction, for method chaining
034 */
035 public JumpInstruction setTarget(Instruction instruction) {
036 _target.setTargetInstruction(instruction);
037 return this;
038 }
039
040 /**
041 * JumpInstructions are equal if they represent the same operation and
042 * the instruction they jump to is the
043 * same, or if the jump Instruction of either is unset.
044 */
045 public boolean equalsInstruction(Instruction other) {
046 if (this == other)
047 return true;
048 if (!super.equalsInstruction(other))
049 return false;
050
051 Instruction target = ((JumpInstruction) other).getTarget();
052 return target == null || getTarget() == null || target == getTarget();
053 }
054
055 public void updateTargets() {
056 _target.updateTargets();
057 }
058
059 public void replaceTarget(Instruction oldTarget, Instruction newTarget) {
060 _target.replaceTarget(oldTarget, newTarget);
061 }
062
063 public void acceptVisit(BCVisitor visit) {
064 visit.enterJumpInstruction(this);
065 visit.exitJumpInstruction(this);
066 }
067
068 void read(Instruction orig) {
069 super.read(orig);
070 _target.setByteIndex(((JumpInstruction) orig)._target.getByteIndex());
071 }
072
073 void read(DataInput in) throws IOException {
074 super.read(in);
075 switch (getOpcode()) {
076 case Constants.GOTOW:
077 case Constants.JSRW:
078 _target.setByteIndex(getByteIndex() + in.readInt());
079 break;
080 default:
081 _target.setByteIndex(getByteIndex() + in.readShort());
082 }
083 }
084
085 void write(DataOutput out) throws IOException {
086 super.write(out);
087 switch (getOpcode()) {
088 case Constants.GOTOW:
089 case Constants.JSRW:
090 out.writeInt(_target.getByteIndex() - getByteIndex());
091 break;
092 default:
093 out.writeShort(_target.getByteIndex() - getByteIndex());
094 }
095 }
096
097 public void setOffset(int offset) {
098 _target.setByteIndex(getByteIndex() + offset);
099 }
100
101 public int getOffset() {
102 return _target.getByteIndex() - getByteIndex();
103 }
104 }