1 21 package proguard.classfile.instruction; 22 23 import proguard.classfile.*; 24 import proguard.classfile.instruction.visitor.InstructionVisitor; 25 import proguard.classfile.attribute.*; 26 27 33 public class VariableInstruction extends Instruction 34 { 35 public boolean wide; 36 public int variableIndex; 37 public int constant; 38 39 40 43 public VariableInstruction() {} 44 45 46 public VariableInstruction(boolean wide) 47 { 48 this.wide = wide; 49 } 50 51 52 public VariableInstruction(byte opcode) 53 { 54 this(opcode, embeddedVariable(opcode), 0); 55 } 56 57 58 public VariableInstruction(byte opcode, 59 int variableIndex) 60 { 61 this(opcode, variableIndex, 0); 62 } 63 64 65 public VariableInstruction(byte opcode, 66 int variableIndex, 67 int constant) 68 { 69 this.opcode = opcode; 70 this.variableIndex = variableIndex; 71 this.constant = constant; 72 this.wide = requiredVariableIndexSize() > 1 || 73 requiredConstantSize() > 1; 74 } 75 76 77 82 public VariableInstruction copy(VariableInstruction variableInstruction) 83 { 84 this.opcode = variableInstruction.opcode; 85 this.variableIndex = variableInstruction.variableIndex; 86 this.constant = variableInstruction.constant; 87 this.wide = variableInstruction.wide; 88 89 return this; 90 } 91 92 93 97 private static int embeddedVariable(byte opcode) 98 { 99 switch (opcode) 100 { 101 case InstructionConstants.OP_ILOAD_1: 102 case InstructionConstants.OP_LLOAD_1: 103 case InstructionConstants.OP_FLOAD_1: 104 case InstructionConstants.OP_DLOAD_1: 105 case InstructionConstants.OP_ALOAD_1: 106 case InstructionConstants.OP_ISTORE_1: 107 case InstructionConstants.OP_LSTORE_1: 108 case InstructionConstants.OP_FSTORE_1: 109 case InstructionConstants.OP_DSTORE_1: 110 case InstructionConstants.OP_ASTORE_1: return 1; 111 112 case InstructionConstants.OP_ILOAD_2: 113 case InstructionConstants.OP_LLOAD_2: 114 case InstructionConstants.OP_FLOAD_2: 115 case InstructionConstants.OP_DLOAD_2: 116 case InstructionConstants.OP_ALOAD_2: 117 case InstructionConstants.OP_ISTORE_2: 118 case InstructionConstants.OP_LSTORE_2: 119 case InstructionConstants.OP_FSTORE_2: 120 case InstructionConstants.OP_DSTORE_2: 121 case InstructionConstants.OP_ASTORE_2: return 2; 122 123 case InstructionConstants.OP_ILOAD_3: 124 case InstructionConstants.OP_LLOAD_3: 125 case InstructionConstants.OP_FLOAD_3: 126 case InstructionConstants.OP_DLOAD_3: 127 case InstructionConstants.OP_ALOAD_3: 128 case InstructionConstants.OP_ISTORE_3: 129 case InstructionConstants.OP_LSTORE_3: 130 case InstructionConstants.OP_FSTORE_3: 131 case InstructionConstants.OP_DSTORE_3: 132 case InstructionConstants.OP_ASTORE_3: return 3; 133 134 default: return 0; 135 } 136 } 137 138 139 144 public boolean isLoad() 145 { 146 return opcode < InstructionConstants.OP_ISTORE && 149 opcode != InstructionConstants.OP_IINC; 150 } 151 152 153 155 public byte canonicalOpcode() 156 { 157 switch (opcode) 159 { 160 case InstructionConstants.OP_ILOAD_0: 161 case InstructionConstants.OP_ILOAD_1: 162 case InstructionConstants.OP_ILOAD_2: 163 case InstructionConstants.OP_ILOAD_3: return InstructionConstants.OP_ILOAD; 164 case InstructionConstants.OP_LLOAD_0: 165 case InstructionConstants.OP_LLOAD_1: 166 case InstructionConstants.OP_LLOAD_2: 167 case InstructionConstants.OP_LLOAD_3: return InstructionConstants.OP_LLOAD; 168 case InstructionConstants.OP_FLOAD_0: 169 case InstructionConstants.OP_FLOAD_1: 170 case InstructionConstants.OP_FLOAD_2: 171 case InstructionConstants.OP_FLOAD_3: return InstructionConstants.OP_FLOAD; 172 case InstructionConstants.OP_DLOAD_0: 173 case InstructionConstants.OP_DLOAD_1: 174 case InstructionConstants.OP_DLOAD_2: 175 case InstructionConstants.OP_DLOAD_3: return InstructionConstants.OP_DLOAD; 176 case InstructionConstants.OP_ALOAD_0: 177 case InstructionConstants.OP_ALOAD_1: 178 case InstructionConstants.OP_ALOAD_2: 179 case InstructionConstants.OP_ALOAD_3: return InstructionConstants.OP_ALOAD; 180 181 case InstructionConstants.OP_ISTORE_0: 182 case InstructionConstants.OP_ISTORE_1: 183 case InstructionConstants.OP_ISTORE_2: 184 case InstructionConstants.OP_ISTORE_3: return InstructionConstants.OP_ISTORE; 185 case InstructionConstants.OP_LSTORE_0: 186 case InstructionConstants.OP_LSTORE_1: 187 case InstructionConstants.OP_LSTORE_2: 188 case InstructionConstants.OP_LSTORE_3: return InstructionConstants.OP_LSTORE; 189 case InstructionConstants.OP_FSTORE_0: 190 case InstructionConstants.OP_FSTORE_1: 191 case InstructionConstants.OP_FSTORE_2: 192 case InstructionConstants.OP_FSTORE_3: return InstructionConstants.OP_FSTORE; 193 case InstructionConstants.OP_DSTORE_0: 194 case InstructionConstants.OP_DSTORE_1: 195 case InstructionConstants.OP_DSTORE_2: 196 case InstructionConstants.OP_DSTORE_3: return InstructionConstants.OP_DSTORE; 197 case InstructionConstants.OP_ASTORE_0: 198 case InstructionConstants.OP_ASTORE_1: 199 case InstructionConstants.OP_ASTORE_2: 200 case InstructionConstants.OP_ASTORE_3: return InstructionConstants.OP_ASTORE; 201 202 default: return opcode; 203 } 204 } 205 206 public Instruction shrink() 207 { 208 opcode = canonicalOpcode(); 209 210 if (variableIndex <= 3) 212 { 213 switch (opcode) 214 { 215 case InstructionConstants.OP_ILOAD: opcode = (byte)(InstructionConstants.OP_ILOAD_0 + variableIndex); break; 216 case InstructionConstants.OP_LLOAD: opcode = (byte)(InstructionConstants.OP_LLOAD_0 + variableIndex); break; 217 case InstructionConstants.OP_FLOAD: opcode = (byte)(InstructionConstants.OP_FLOAD_0 + variableIndex); break; 218 case InstructionConstants.OP_DLOAD: opcode = (byte)(InstructionConstants.OP_DLOAD_0 + variableIndex); break; 219 case InstructionConstants.OP_ALOAD: opcode = (byte)(InstructionConstants.OP_ALOAD_0 + variableIndex); break; 220 221 case InstructionConstants.OP_ISTORE: opcode = (byte)(InstructionConstants.OP_ISTORE_0 + variableIndex); break; 222 case InstructionConstants.OP_LSTORE: opcode = (byte)(InstructionConstants.OP_LSTORE_0 + variableIndex); break; 223 case InstructionConstants.OP_FSTORE: opcode = (byte)(InstructionConstants.OP_FSTORE_0 + variableIndex); break; 224 case InstructionConstants.OP_DSTORE: opcode = (byte)(InstructionConstants.OP_DSTORE_0 + variableIndex); break; 225 case InstructionConstants.OP_ASTORE: opcode = (byte)(InstructionConstants.OP_ASTORE_0 + variableIndex); break; 226 } 227 } 228 229 wide = requiredVariableIndexSize() > 1 || 231 requiredConstantSize() > 1; 232 233 return this; 234 } 235 236 237 protected boolean isWide() 238 { 239 return wide; 240 } 241 242 243 protected void readInfo(byte[] code, int offset) 244 { 245 int variableIndexSize = variableIndexSize(); 246 int constantSize = constantSize(); 247 248 if (variableIndexSize == 0) 250 { 251 variableIndex = opcode < InstructionConstants.OP_ISTORE_0 ? 253 (opcode - InstructionConstants.OP_ILOAD_0 ) & 3 : 254 (opcode - InstructionConstants.OP_ISTORE_0) & 3; 255 } 256 else 257 { 258 variableIndex = readValue(code, offset, variableIndexSize); offset += variableIndexSize; 259 } 260 261 constant = readSignedValue(code, offset, constantSize); 262 } 263 264 265 protected void writeInfo(byte[] code, int offset) 266 { 267 int variableIndexSize = variableIndexSize(); 268 int constantSize = constantSize(); 269 270 if (requiredVariableIndexSize() > variableIndexSize) 271 { 272 throw new IllegalArgumentException ("Instruction has invalid variable index size ("+this.toString(offset)+")"); 273 } 274 275 if (requiredConstantSize() > constantSize) 276 { 277 throw new IllegalArgumentException ("Instruction has invalid constant size ("+this.toString(offset)+")"); 278 } 279 280 writeValue(code, offset, variableIndex, variableIndexSize); offset += variableIndexSize; 281 writeSignedValue(code, offset, constant, constantSize); 282 } 283 284 285 public int length(int offset) 286 { 287 return (wide ? 2 : 1) + variableIndexSize() + constantSize(); 288 } 289 290 291 public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor) 292 { 293 instructionVisitor.visitVariableInstruction(clazz, method, codeAttribute, offset, this); 294 } 295 296 297 299 public String toString() 300 { 301 return getName() + 302 (wide ? "_w" : "") + 303 " v"+variableIndex + 304 (constantSize() > 0 ? ", "+constant : ""); 305 } 306 307 308 310 313 private int variableIndexSize() 314 { 315 return (opcode >= InstructionConstants.OP_ILOAD_0 && 316 opcode <= InstructionConstants.OP_ALOAD_3) || 317 (opcode >= InstructionConstants.OP_ISTORE_0 && 318 opcode <= InstructionConstants.OP_ASTORE_3) ? 0 : 319 wide ? 2 : 320 1; 321 } 322 323 324 328 private int requiredVariableIndexSize() 329 { 330 return (variableIndex & 0x3) == variableIndex ? 0 : 331 (variableIndex & 0xff) == variableIndex ? 1 : 332 (variableIndex & 0xffff) == variableIndex ? 2 : 333 4; 334 335 } 336 337 338 341 private int constantSize() 342 { 343 return opcode != InstructionConstants.OP_IINC ? 0 : 344 wide ? 2 : 345 1; 346 } 347 348 349 352 private int requiredConstantSize() 353 { 354 return opcode != InstructionConstants.OP_IINC ? 0 : 355 constant << 24 >> 24 == constant ? 1 : 356 constant << 16 >> 16 == constant ? 2 : 357 4; 358 } 359 } 360 | Popular Tags |