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.classFile.constantPool.ConstantPool;
005
006 /**
007 * Abstract Java instruction.
008 *
009 * @author Mathias Ricken
010 */
011 public abstract class AInstruction {
012 /**
013 * Get the bytecode for this instruction, padded for the specified program counter value, with branch targets
014 * according to the specified line number table
015 *
016 * @param pc PC for padding
017 * @param lnt line number table for branches
018 *
019 * @return bytecode
020 */
021 public abstract byte[] getBytecode(int pc, LineNumberTable lnt);
022
023 /**
024 * Get the opcode of this instruction.
025 *
026 * @return opcode
027 */
028 public abstract byte getOpcode();
029
030 /**
031 * Get the length bytecode for this instruction, padded for the specified program counter value.
032 *
033 * @param pc PC for padding
034 *
035 * @return bytecode length
036 */
037 public abstract int getBytecodeLength(int pc);
038
039 /**
040 * Return an array of target indices.
041 *
042 * @return array of target indices.
043 */
044 public abstract int[] getBranchTargets();
045
046 /**
047 * Set the branch target indices.
048 *
049 * @param branchTargets array of target indices
050 */
051 public abstract void setBranchTargets(int[] branchTargets);
052
053 /**
054 * Make an instruction from the bytecode starting at pc, using the specified padding PC and the line number table.
055 *
056 * @param bytecode bytecode
057 * @param pc start PC in bytecode
058 * @param paddingPC PC used for padding
059 * @param lnt line number table for branches
060 *
061 * @return instruction
062 */
063 public static AInstruction makeInstruction(byte[] bytecode, int pc, int paddingPC, LineNumberTable lnt) {
064 byte o = bytecode[pc];
065 switch(o) {
066 case Opcode.TABLESWITCH:
067 return new TableSwitchInstruction(bytecode, pc, paddingPC, lnt);
068
069 case Opcode.LOOKUPSWITCH:
070 return new LookupSwitchInstruction(bytecode, pc, paddingPC, lnt);
071
072 case Opcode.IFEQ:
073 case Opcode.IFNE:
074 case Opcode.IFLT:
075 case Opcode.IFGE:
076 case Opcode.IFGT:
077 case Opcode.IFLE:
078 case Opcode.IF_ICMPEQ:
079 case Opcode.IF_ICMPNE:
080 case Opcode.IF_ICMPLT:
081 case Opcode.IF_ICMPGE:
082 case Opcode.IF_ICMPGT:
083 case Opcode.IF_ICMPLE:
084 case Opcode.IF_ACMPEQ:
085 case Opcode.IF_ACMPNE:
086 case Opcode.GOTO:
087 case Opcode.JSR:
088 case Opcode.IFNULL:
089 case Opcode.IFNONNULL:
090 return new BranchInstruction(bytecode, pc, paddingPC, lnt);
091
092 case Opcode.GOTO_W:
093 case Opcode.JSR_W:
094 return new WideBranchInstruction(bytecode, pc, paddingPC, lnt);
095
096 case Opcode.WIDE:
097 return new WideInstruction(bytecode, pc, paddingPC, lnt);
098
099 case Opcode.INVOKESTATIC:
100 case Opcode.INVOKESPECIAL:
101 case Opcode.INVOKEVIRTUAL:
102 case Opcode.CHECKCAST:
103 case Opcode.GETFIELD:
104 case Opcode.GETSTATIC:
105 case Opcode.INSTANCEOF:
106 case Opcode.NEW:
107 case Opcode.PUTFIELD:
108 case Opcode.PUTSTATIC:
109 case Opcode.ANEWARRAY:
110 case Opcode.LDC:
111 case Opcode.LDC_W:
112 case Opcode.LDC2_W:
113 return new ReferenceInstruction(bytecode, pc, paddingPC, lnt);
114
115 default:
116 return new GenericInstruction(bytecode, pc, paddingPC, lnt);
117 }
118 }
119
120 /**
121 * Return true of this instruction and the other object are equal.
122 *
123 * @param o other object
124 *
125 * @return true if equal
126 */
127 public abstract boolean equals(Object o);
128
129 /**
130 * Return hash code.
131 *
132 * @return hash code
133 */
134 public abstract int hashCode();
135
136 /**
137 * Return a verbose string representation.
138 * @param cp constant pool
139 * @return verbose string representation
140 */
141 public String toStringVerbose(ConstantPool cp) {
142 return toString();
143 }
144
145 /**
146 * Returns a store instruction that corresponds to the given load instruction.
147 * @param loadInstruction load instruction
148 * @return corresponding store instruction
149 */
150 public static AInstruction getCorrespondingStore(AInstruction loadInstruction) {
151 byte opcode = loadInstruction.getOpcode();
152 if (opcode==Opcode.WIDE) {
153 WideInstruction wi = (WideInstruction)loadInstruction;
154 byte[] code = wi.getBytecode();
155 byte opcode2 = code[1];
156 if ((opcode2>=Opcode.ILOAD) && (opcode2<=Opcode.ALOAD)) {
157 // WIDE ILOAD 0x15 -> WIDE ISTORE 0x36;
158 // WIDE LLOAD 0x16 -> WIDE LSTORE 0x37;
159 // WIDE FLOAD 0x17 -> WIDE FSTORE 0x38;
160 // WIDE DLOAD 0x18 -> WIDE DSTORE 0x39;
161 // WIDE ALOAD 0x19 -> WIDE ASTORE 0x3A;
162 return new WideInstruction(new byte[] {(byte)(opcode2 + (Opcode.ISTORE-Opcode.ILOAD)), code[2], code[3]});
163 }
164 }
165 else if ((opcode>=Opcode.ILOAD) && (opcode<=Opcode.ALOAD)) {
166 // ILOAD 0x15 -> ISTORE 0x36;
167 // LLOAD 0x16 -> LSTORE 0x37;
168 // FLOAD 0x17 -> FSTORE 0x38;
169 // DLOAD 0x18 -> DSTORE 0x39;
170 // ALOAD 0x19 -> ASTORE 0x3A;
171 GenericInstruction gi = (GenericInstruction)loadInstruction;
172 byte[] code = gi.getBytecode();
173 return new GenericInstruction(new byte[] {(byte)(opcode + (Opcode.ISTORE-Opcode.ILOAD)), code[1]});
174 }
175 else if ((opcode>=Opcode.ILOAD_0) && (opcode<=Opcode.ALOAD_3)) {
176 // ILOAD_0 0x1A -> ISTORE_0 0x3B;
177 // ILOAD_1 0x1B -> ISTORE_1 0x3C;
178 // ILOAD_2 0x1C -> ISTORE_2 0x3D;
179 // ILOAD_3 0x1D -> ISTORE_3 0x3E;
180 // LLOAD_0 0x1E -> LSTORE_0 0x3F;
181 // LLOAD_1 0x1F -> LSTORE_1 0x40;
182 // LLOAD_2 0x20 -> LSTORE_2 0x41;
183 // LLOAD_3 0x21 -> LSTORE_3 0x42;
184 // FLOAD_0 0x22 -> FSTORE_0 0x43;
185 // FLOAD_1 0x23 -> FSTORE_1 0x44;
186 // FLOAD_2 0x24 -> FSTORE_2 0x45;
187 // FLOAD_3 0x25 -> FSTORE_3 0x46;
188 // DLOAD_0 0x26 -> DSTORE_0 0x47;
189 // DLOAD_1 0x27 -> DSTORE_1 0x48;
190 // DLOAD_2 0x28 -> DSTORE_2 0x49;
191 // DLOAD_3 0x29 -> DSTORE_3 0x4A;
192 // ALOAD_0 0x2A -> ASTORE_0 0x4B;
193 // ALOAD_1 0x2B -> ASTORE_1 0x4C;
194 // ALOAD_2 0x2C -> ASTORE_2 0x4D;
195 // ALOAD_3 0x2D -> ASTORE_3 0x4E;
196 return new GenericInstruction(new byte[] {(byte)(opcode + (Opcode.ISTORE_0-Opcode.ILOAD_0))});
197 }
198 else if ((opcode>=Opcode.IALOAD) && (opcode<=Opcode.SALOAD)) {
199 // IALOAD 0x2E -> IASTORE 0x4F;
200 // LALOAD 0x2F -> LASTORE 0x50;
201 // FALOAD 0x30 -> FASTORE 0x51;
202 // DALOAD 0x31 -> DASTORE 0x52;
203 // AALOAD 0x32 -> AASTORE 0x53;
204 // BALOAD 0x33 -> BASTORE 0x54;
205 // CALOAD 0x34 -> CASTORE 0x55;
206 // SALOAD 0x35 -> SASTORE 0x56;
207 GenericInstruction gi = (GenericInstruction)loadInstruction;
208 byte[] code = gi.getBytecode();
209 return new GenericInstruction(new byte[] {(byte)(opcode + (Opcode.ISTORE-Opcode.ILOAD))});
210 }
211 throw new IllegalArgumentException("Invalid load instruction");
212 }
213
214 /**
215 * Returns a load instruction that corresponds to the given store instruction.
216 * @param storeInstruction store instruction
217 * @return corresponding load instruction
218 */
219 public static AInstruction getCorrespondingLoad(AInstruction storeInstruction) {
220 byte opcode = storeInstruction.getOpcode();
221 if (opcode==Opcode.WIDE) {
222 WideInstruction wi = (WideInstruction)storeInstruction;
223 byte[] code = wi.getBytecode();
224 byte opcode2 = code[1];
225 if ((opcode2>=Opcode.ISTORE) && (opcode2<=Opcode.ASTORE)) {
226 // WIDE ISTORE 0x36 -> WIDE ILOAD 0x15;
227 // WIDE LSTORE 0x37 -> WIDE LLOAD 0x16;
228 // WIDE FSTORE 0x38 -> WIDE FLOAD 0x17;
229 // WIDE DSTORE 0x39 -> WIDE DLOAD 0x18;
230 // WIDE ASTORE 0x3A -> WIDE ALOAD 0x19;
231 return new WideInstruction(new byte[] {(byte)(opcode2 - (Opcode.ISTORE-Opcode.ILOAD)), code[2], code[3]});
232 }
233 }
234 else if ((opcode>=Opcode.ISTORE) && (opcode<=Opcode.ASTORE)) {
235 // ISTORE 0x36 -> ILOAD 0x15;
236 // LSTORE 0x37 -> LLOAD 0x16;
237 // FSTORE 0x38 -> FLOAD 0x17;
238 // DSTORE 0x39 -> DLOAD 0x18;
239 // ASTORE 0x3A -> ALOAD 0x19;
240 GenericInstruction gi = (GenericInstruction)storeInstruction;
241 byte[] code = gi.getBytecode();
242 return new GenericInstruction(new byte[] {(byte)(opcode - (Opcode.ISTORE-Opcode.ILOAD)), code[1]});
243 }
244 else if ((opcode>=Opcode.ISTORE_0) && (opcode<=Opcode.ASTORE_3)) {
245 // ISTORE_0 0x3B -> ILOAD_0 0x1A;
246 // ISTORE_1 0x3C -> ILOAD_1 0x1B;
247 // ISTORE_2 0x3D -> ILOAD_2 0x1C;
248 // ISTORE_3 0x3E -> ILOAD_3 0x1D;
249 // LSTORE_0 0x3F -> LLOAD_0 0x1E;
250 // LSTORE_1 0x40 -> LLOAD_1 0x1F;
251 // LSTORE_2 0x41 -> LLOAD_2 0x20;
252 // LSTORE_3 0x42 -> LLOAD_3 0x21;
253 // FSTORE_0 0x43 -> FLOAD_0 0x22;
254 // FSTORE_1 0x44 -> FLOAD_1 0x23;
255 // FSTORE_2 0x45 -> FLOAD_2 0x24;
256 // FSTORE_3 0x46 -> FLOAD_3 0x25;
257 // DSTORE_0 0x47 -> DLOAD_0 0x26;
258 // DSTORE_1 0x48 -> DLOAD_1 0x27;
259 // DSTORE_2 0x49 -> DLOAD_2 0x28;
260 // DSTORE_3 0x4A -> DLOAD_3 0x29;
261 // ASTORE_0 0x4B -> ALOAD_0 0x2A;
262 // ASTORE_1 0x4C -> ALOAD_1 0x2B;
263 // ASTORE_2 0x4D -> ALOAD_2 0x2C;
264 // ASTORE_3 0x4E -> ALOAD_3 0x2D;
265 return new GenericInstruction(new byte[] {(byte)(opcode - (Opcode.ISTORE_0-Opcode.ILOAD_0))});
266 }
267 else if ((opcode>=Opcode.IASTORE) && (opcode<=Opcode.SASTORE)) {
268 // IASTORE 0x4F -> IALOAD 0x2E;
269 // LASTORE 0x50 -> LALOAD 0x2F;
270 // FASTORE 0x51 -> FALOAD 0x30;
271 // DASTORE 0x52 -> DALOAD 0x31;
272 // AASTORE 0x53 -> AALOAD 0x32;
273 // BASTORE 0x54 -> BALOAD 0x33;
274 // CASTORE 0x55 -> CALOAD 0x34;
275 // SASTORE 0x56 -> SALOAD 0x35;
276 GenericInstruction gi = (GenericInstruction)storeInstruction;
277 byte[] code = gi.getBytecode();
278 return new GenericInstruction(new byte[] {(byte)(opcode - (Opcode.IASTORE-Opcode.IALOAD))});
279 }
280 throw new IllegalArgumentException("Invalid store instruction");
281 }
282 }
283