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