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