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 }