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