001 package edu.rice.cs.cunit.classFile.code.instructions;
002
003 import edu.rice.cs.cunit.classFile.code.Opcode;
004 import edu.rice.cs.cunit.util.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 int getBytecodeLength(int 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, int pc, int 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(int 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 final WideBranchInstruction wideBranchInstruction = (WideBranchInstruction)o;
108
109 if (_opcode != wideBranchInstruction._opcode) {
110 return false;
111 }
112 if (_target != wideBranchInstruction._target) {
113 return false;
114 }
115
116 return true;
117 }
118
119 /**
120 * Return hash code.
121 *
122 * @return hash code
123 */
124 public int hashCode() {
125 int result;
126 result = (int)_opcode;
127 result = 29 * result + _target;
128 return result;
129 }
130
131 /**
132 * Return an array of target indices.
133 *
134 * @return array of target indices.
135 */
136 public int[] getBranchTargets() {
137 return new int[]{
138 _target
139 };
140 }
141
142 /**
143 * Set the branch target indices.
144 *
145 * @param branchTargets array of target indices
146 */
147 public void setBranchTargets(int[] branchTargets) {
148 if (branchTargets.length != 1) {
149 throw new IllegalArgumentException("Wide branch instruction can only have one target");
150 }
151 _target = branchTargets[0];
152 }
153
154
155 /**
156 * Return instruction in human-readable form.
157 *
158 * @return string representation
159 */
160 public String toString() {
161 StringBuilder x = new StringBuilder();
162 x.append(Opcode.getOpcodeName(_opcode));
163 x.append(" ");
164 x.append(_target);
165 return x.toString();
166 }
167 }
168