001 package sysModel.classFile.code.instructions;
002
003 import sysModel.classFile.code.Opcode;
004 import sysModel.classFile.Types;
005
006 /**
007 * Wide branch Java instruction.
008 *
009 * @author Mathias Ricken
010 */
011 public class WideBranchInstruction extends AInstruction {
012 /**
013 * Opcode.
014 */
015 protected byte _opcode;
016
017 /**
018 * Branch target.
019 */
020 protected int _target;
021
022 /**
023 * Constructor.
024 *
025 * @param opcode branch opcode
026 * @param target target line number
027 */
028 public WideBranchInstruction(byte opcode, int target) {
029 switch(opcode) {
030 case Opcode.GOTO_W:
031 case Opcode.JSR_W:
032 break;
033 default:
034 throw new IllegalArgumentException("Invalid wide branch opcode");
035 }
036 _opcode = opcode;
037 _target = target;
038 }
039
040 /**
041 * Get the opcode of this instruction.
042 *
043 * @return opcode
044 */
045 public byte getOpcode() {
046 return _opcode;
047 }
048
049 /**
050 * Get the length bytecode for this instruction, padded for the specified program counter value.
051 *
052 * @param pc PC for padding
053 *
054 * @return bytecode length
055 */
056 public short getBytecodeLength(short pc) {
057 return 5;
058 }
059
060 /**
061 * Make a new wide branch instruction from the bytecode stating at pc, padded using paddingPC, and use the line
062 * number table for branches.
063 *
064 * @param bytecode bytecode
065 * @param pc starting index in bytecode
066 * @param paddingPC PC for padding
067 * @param lnt line number table for branches
068 */
069 public WideBranchInstruction(byte[] bytecode, short pc, short paddingPC, LineNumberTable lnt) {
070 _opcode = bytecode[pc];
071 _target = lnt.getLineNumber(pc + Types.intFromBytes(bytecode, pc + 1));
072 }
073
074 /**
075 * Get the bytecode for this instruction, padded for the specified program counter value, with branch targets
076 * according to the specified line number table
077 *
078 * @param pc PC for padding
079 * @param lnt line number table for branches
080 *
081 * @return bytecode
082 */
083 public byte[] getBytecode(short pc, LineNumberTable lnt) {
084 byte[] b = new byte[getBytecodeLength(pc)];
085
086 b[0] = getOpcode();
087 Types.bytesFromInt(lnt.getPC(_target) - pc, b, 1);
088
089 return b;
090 }
091
092 /**
093 * Return true of this instruction and the other object are equal.
094 *
095 * @param o other object
096 *
097 * @return true if equal
098 */
099 public boolean equals(Object o) {
100 if (this == o) {
101 return true;
102 }
103 if (!(o instanceof WideBranchInstruction)) {
104 return false;
105 }
106
107 WideBranchInstruction wideBranchInstruction = (WideBranchInstruction)o;
108
109 if (_opcode != wideBranchInstruction._opcode) {
110 return false;
111 }
112 return _target == wideBranchInstruction._target;
113
114 }
115
116 /**
117 * Return hash code.
118 *
119 * @return hash code
120 */
121 public int hashCode() {
122 int result;
123 result = (int)_opcode;
124 result = 29 * result + _target;
125 return result;
126 }
127
128 /**
129 * Return an array of target indices.
130 *
131 * @return array of target indices.
132 */
133 public short[] getBranchTargets() {
134 return new short[]{
135 (short)_target
136 };
137 }
138
139 /**
140 * Set the branch target indices.
141 *
142 * @param branchTargets array of target indices
143 */
144 public void setBranchTargets(short[] branchTargets) {
145 if (1 != branchTargets.length) {
146 throw new IllegalArgumentException("Wide branch instruction can only have one target");
147 }
148 _target = branchTargets[0];
149 }
150
151
152 /**
153 * Return instruction in human-readable form.
154 *
155 * @return string representation
156 */
157 public String toString() {
158 StringBuffer x = new StringBuffer();
159 x.append(Opcode.getOpcodeName(_opcode));
160 x.append(' ');
161 x.append(_target);
162 return x.toString();
163 }
164 }
165