001 package edu.rice.cs.cunit.classFile.code.instructions;
002
003 import edu.rice.cs.cunit.classFile.code.Opcode;
004
005 import java.util.Arrays;
006
007 /**
008 * Generic Java instruction.
009 *
010 * @author Mathias Ricken
011 */
012 public class GenericInstruction extends AInstruction {
013 /**
014 * Bytecode.
015 */
016 protected byte[] _code;
017
018 /**
019 * Constructor.
020 *
021 * @param code bytecode for generic instruction
022 */
023 public GenericInstruction(byte... code) {
024 switch(code[0]) {
025 case Opcode.TABLESWITCH:
026 case Opcode.LOOKUPSWITCH:
027 case Opcode.IFEQ:
028 case Opcode.IFNE:
029 case Opcode.IFLT:
030 case Opcode.IFGE:
031 case Opcode.IFGT:
032 case Opcode.IFLE:
033 case Opcode.IF_ICMPEQ:
034 case Opcode.IF_ICMPNE:
035 case Opcode.IF_ICMPLT:
036 case Opcode.IF_ICMPGE:
037 case Opcode.IF_ICMPGT:
038 case Opcode.IF_ICMPLE:
039 case Opcode.IF_ACMPEQ:
040 case Opcode.IF_ACMPNE:
041 case Opcode.GOTO:
042 case Opcode.JSR:
043 case Opcode.IFNULL:
044 case Opcode.IFNONNULL:
045 case Opcode.GOTO_W:
046 case Opcode.JSR_W:
047 case Opcode.WIDE:
048 throw new IllegalArgumentException("Invalid generic opcode");
049 }
050 _code = code;
051 }
052
053 /**
054 * Get the opcode of this instruction.
055 *
056 * @return opcode
057 */
058 public byte getOpcode() {
059 return _code[0];
060 }
061
062 /**
063 * Get the length bytecode for this instruction, padded for the specified program counter value.
064 *
065 * @param pc PC for padding
066 *
067 * @return bytecode length
068 */
069 public int getBytecodeLength(int pc) {
070 return Opcode.getInstrSize(_code, 0, 0);
071 }
072
073 /**
074 * Make a new generic instruction from the bytecode stating at pc, padded using paddingPC, and use the line number
075 * table for branches.
076 *
077 * @param bytecode bytecode
078 * @param pc starting index in bytecode
079 * @param paddingPC PC for padding
080 * @param lnt line number table for branches
081 */
082 public GenericInstruction(byte[] bytecode, int pc, int paddingPC, LineNumberTable lnt) {
083 _code = new byte[Opcode.getInstrSize(bytecode, pc, paddingPC)];
084 System.arraycopy(bytecode, pc, _code, 0, _code.length);
085 }
086
087 /**
088 * Get the bytecode for this instruction, padded for the specified program counter value, with branch targets
089 * according to the specified line number table
090 *
091 * @param pc PC for padding
092 * @param lnt line number table for branches
093 *
094 * @return bytecode
095 */
096 public byte[] getBytecode(int pc, LineNumberTable lnt) {
097 return getBytecode();
098 }
099
100 /**
101 * Get the bytecode for this instruction.
102 *
103 * @return bytecode
104 */
105 public byte[] getBytecode() {
106 byte[] b = new byte[_code.length];
107 System.arraycopy(_code, 0, b, 0, _code.length);
108 return b;
109 }
110
111 /**
112 * Return true of this instruction and the other object are equal.
113 *
114 * @param o other object
115 *
116 * @return true if equal
117 */
118 public boolean equals(Object o) {
119 if (this == o) {
120 return true;
121 }
122 if (!(o instanceof GenericInstruction)) {
123 return false;
124 }
125
126 final GenericInstruction genericInstruction = (GenericInstruction)o;
127
128 if (!Arrays.equals(_code, genericInstruction._code)) {
129 return false;
130 }
131
132 return true;
133 }
134
135 /**
136 * Return hash code.
137 *
138 * @return hash code
139 */
140 public int hashCode() {
141 return _code[0];
142 }
143
144 /**
145 * Return an array of target indices.
146 *
147 * @return array of target indices.
148 */
149 public int[] getBranchTargets() {
150 return new int[0];
151 }
152
153 /**
154 * Set the branch target indices.
155 *
156 * @param branchTargets array of target indices
157 */
158 public void setBranchTargets(int[] branchTargets) {
159 if (branchTargets.length != 0) {
160 throw new IllegalArgumentException("Generic instruction cannot have a target");
161 }
162 }
163
164 /**
165 * Return instruction in human-readable form.
166 *
167 * @return string representation
168 */
169 public String toString() {
170 StringBuilder x = new StringBuilder();
171 x.append(Opcode.getOpcodeName(_code[0]));
172 x.append(" ");
173 for(int i = 1; i < _code.length; ++i) {
174 x.append(String.format("%02x", new Object[]{new Byte(_code[i])}) + " ");
175 }
176 return x.toString();
177 }
178 }
179