1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric (at) graphics.cornell.edu) 6 * 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 * 12 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.evaluation; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.CodeAttribute; 25 import proguard.classfile.instruction.*; 26 import proguard.classfile.instruction.visitor.InstructionVisitor; 27 import proguard.evaluation.value.*; 28 29 /** 30 * This InstructionVisitor executes the instructions that it visits on a given 31 * local variable frame and stack. 32 * 33 * @author Eric Lafortune 34 */ 35 public class Processor 36 implements InstructionVisitor 37 { 38 private final Variables variables; 39 private final Stack stack; 40 private final ValueFactory valueFactory; 41 private final BranchUnit branchUnit; 42 private final InvocationUnit invocationUnit; 43 private final boolean alwaysCast; 44 45 private final ConstantValueFactory constantValueFactory; 46 private final ClassConstantValueFactory classConstantValueFactory; 47 48 49 /** 50 * Creates a new processor that operates on the given environment. 51 * @param variables the local variable frame. 52 * @param stack the local stack. 53 * @param branchUnit the class that can affect the program counter. 54 * @param invocationUnit the class that can access other program members. 55 * @param alwaysCast a flag that specifies whether downcasts or casts 56 * of null values should always be performed. 57 */ 58 public Processor(Variables variables, 59 Stack stack, 60 ValueFactory valueFactory, 61 BranchUnit branchUnit, 62 InvocationUnit invocationUnit, 63 boolean alwaysCast) 64 { 65 this.variables = variables; 66 this.stack = stack; 67 this.valueFactory = valueFactory; 68 this.branchUnit = branchUnit; 69 this.invocationUnit = invocationUnit; 70 this.alwaysCast = alwaysCast; 71 72 constantValueFactory = new ConstantValueFactory(valueFactory); 73 classConstantValueFactory = new ClassConstantValueFactory(valueFactory); 74 } 75 76 77 // Implementations for InstructionVisitor. 78 79 public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) 80 { 81 switch (simpleInstruction.opcode) 82 { 83 case InstructionConstants.OP_NOP: 84 break; 85 86 case InstructionConstants.OP_ACONST_NULL: 87 stack.push(valueFactory.createReferenceValueNull()); 88 break; 89 90 case InstructionConstants.OP_ICONST_M1: 91 case InstructionConstants.OP_ICONST_0: 92 case InstructionConstants.OP_ICONST_1: 93 case InstructionConstants.OP_ICONST_2: 94 case InstructionConstants.OP_ICONST_3: 95 case InstructionConstants.OP_ICONST_4: 96 case InstructionConstants.OP_ICONST_5: 97 case InstructionConstants.OP_BIPUSH: 98 case InstructionConstants.OP_SIPUSH: 99 stack.push(valueFactory.createIntegerValue(simpleInstruction.constant)); 100 break; 101 102 case InstructionConstants.OP_LCONST_0: 103 case InstructionConstants.OP_LCONST_1: 104 stack.push(valueFactory.createLongValue(simpleInstruction.constant)); 105 break; 106 107 case InstructionConstants.OP_FCONST_0: 108 case InstructionConstants.OP_FCONST_1: 109 case InstructionConstants.OP_FCONST_2: 110 stack.push(valueFactory.createFloatValue((float)simpleInstruction.constant)); 111 break; 112 113 case InstructionConstants.OP_DCONST_0: 114 case InstructionConstants.OP_DCONST_1: 115 stack.push(valueFactory.createDoubleValue((double)simpleInstruction.constant)); 116 break; 117 118 case InstructionConstants.OP_IALOAD: 119 case InstructionConstants.OP_BALOAD: 120 case InstructionConstants.OP_CALOAD: 121 case InstructionConstants.OP_SALOAD: 122 { 123 IntegerValue arrayIndex = stack.ipop(); 124 ReferenceValue arrayReference = stack.apop(); 125 stack.push(arrayReference.integerArrayLoad(arrayIndex, valueFactory)); 126 break; 127 } 128 case InstructionConstants.OP_LALOAD: 129 { 130 IntegerValue arrayIndex = stack.ipop(); 131 ReferenceValue arrayReference = stack.apop(); 132 stack.push(arrayReference.longArrayLoad(arrayIndex, valueFactory)); 133 break; 134 } 135 case InstructionConstants.OP_FALOAD: 136 { 137 IntegerValue arrayIndex = stack.ipop(); 138 ReferenceValue arrayReference = stack.apop(); 139 stack.push(arrayReference.floatArrayLoad(arrayIndex, valueFactory)); 140 break; 141 } 142 case InstructionConstants.OP_DALOAD: 143 { 144 IntegerValue arrayIndex = stack.ipop(); 145 ReferenceValue arrayReference = stack.apop(); 146 stack.push(arrayReference.doubleArrayLoad(arrayIndex, valueFactory)); 147 break; 148 } 149 case InstructionConstants.OP_AALOAD: 150 { 151 IntegerValue arrayIndex = stack.ipop(); 152 ReferenceValue arrayReference = stack.apop(); 153 stack.push(arrayReference.referenceArrayLoad(arrayIndex, valueFactory)); 154 break; 155 } 156 case InstructionConstants.OP_IASTORE: 157 case InstructionConstants.OP_BASTORE: 158 case InstructionConstants.OP_CASTORE: 159 case InstructionConstants.OP_SASTORE: 160 { 161 Value value = stack.ipop(); 162 IntegerValue arrayIndex = stack.ipop(); 163 ReferenceValue arrayReference = stack.apop(); 164 arrayReference.arrayStore(arrayIndex, value); 165 break; 166 } 167 case InstructionConstants.OP_LASTORE: 168 { 169 Value value = stack.lpop(); 170 IntegerValue arrayIndex = stack.ipop(); 171 ReferenceValue arrayReference = stack.apop(); 172 arrayReference.arrayStore(arrayIndex, value); 173 break; 174 } 175 case InstructionConstants.OP_FASTORE: 176 { 177 Value value = stack.fpop(); 178 IntegerValue arrayIndex = stack.ipop(); 179 ReferenceValue arrayReference = stack.apop(); 180 arrayReference.arrayStore(arrayIndex, value); 181 break; 182 } 183 case InstructionConstants.OP_DASTORE: 184 { 185 Value value = stack.dpop(); 186 IntegerValue arrayIndex = stack.ipop(); 187 ReferenceValue arrayReference = stack.apop(); 188 arrayReference.arrayStore(arrayIndex, value); 189 break; 190 } 191 case InstructionConstants.OP_AASTORE: 192 { 193 Value value = stack.apop(); 194 IntegerValue arrayIndex = stack.ipop(); 195 ReferenceValue arrayReference = stack.apop(); 196 arrayReference.arrayStore(arrayIndex, value); 197 break; 198 } 199 case InstructionConstants.OP_POP: 200 stack.pop1(); 201 break; 202 203 case InstructionConstants.OP_POP2: 204 stack.pop2(); 205 break; 206 207 case InstructionConstants.OP_DUP: 208 stack.dup(); 209 break; 210 211 case InstructionConstants.OP_DUP_X1: 212 stack.dup_x1(); 213 break; 214 215 case InstructionConstants.OP_DUP_X2: 216 stack.dup_x2(); 217 break; 218 219 case InstructionConstants.OP_DUP2: 220 stack.dup2(); 221 break; 222 223 case InstructionConstants.OP_DUP2_X1: 224 stack.dup2_x1(); 225 break; 226 227 case InstructionConstants.OP_DUP2_X2: 228 stack.dup2_x2(); 229 break; 230 231 case InstructionConstants.OP_SWAP: 232 stack.swap(); 233 break; 234 235 case InstructionConstants.OP_IADD: 236 stack.push(stack.ipop().add(stack.ipop())); 237 break; 238 239 case InstructionConstants.OP_LADD: 240 stack.push(stack.lpop().add(stack.lpop())); 241 break; 242 243 case InstructionConstants.OP_FADD: 244 stack.push(stack.fpop().add(stack.fpop())); 245 break; 246 247 case InstructionConstants.OP_DADD: 248 stack.push(stack.dpop().add(stack.dpop())); 249 break; 250 251 case InstructionConstants.OP_ISUB: 252 stack.push(stack.ipop().subtractFrom(stack.ipop())); 253 break; 254 255 case InstructionConstants.OP_LSUB: 256 stack.push(stack.lpop().subtractFrom(stack.lpop())); 257 break; 258 259 case InstructionConstants.OP_FSUB: 260 stack.push(stack.fpop().subtractFrom(stack.fpop())); 261 break; 262 263 case InstructionConstants.OP_DSUB: 264 stack.push(stack.dpop().subtractFrom(stack.dpop())); 265 break; 266 267 case InstructionConstants.OP_IMUL: 268 stack.push(stack.ipop().multiply(stack.ipop())); 269 break; 270 271 case InstructionConstants.OP_LMUL: 272 stack.push(stack.lpop().multiply(stack.lpop())); 273 break; 274 275 case InstructionConstants.OP_FMUL: 276 stack.push(stack.fpop().multiply(stack.fpop())); 277 break; 278 279 case InstructionConstants.OP_DMUL: 280 stack.push(stack.dpop().multiply(stack.dpop())); 281 break; 282 283 case InstructionConstants.OP_IDIV: 284 try 285 { 286 stack.push(stack.ipop().divideOf(stack.ipop())); 287 } 288 catch (ArithmeticException ex) 289 { 290 stack.push(valueFactory.createIntegerValue()); 291 // TODO: Forward ArithmeticExceptions. 292 //stack.clear(); 293 //stack.push(valueFactory.createReference(false)); 294 //branchUnit.throwException(); 295 } 296 break; 297 298 case InstructionConstants.OP_LDIV: 299 try 300 { 301 stack.push(stack.lpop().divideOf(stack.lpop())); 302 } 303 catch (ArithmeticException ex) 304 { 305 stack.push(valueFactory.createLongValue()); 306 // TODO: Forward ArithmeticExceptions. 307 //stack.clear(); 308 //stack.push(valueFactory.createReference(false)); 309 //branchUnit.throwException(); 310 } 311 break; 312 313 case InstructionConstants.OP_FDIV: 314 stack.push(stack.fpop().divideOf(stack.fpop())); 315 break; 316 317 case InstructionConstants.OP_DDIV: 318 stack.push(stack.dpop().divideOf(stack.dpop())); 319 break; 320 321 case InstructionConstants.OP_IREM: 322 try 323 { 324 stack.push(stack.ipop().remainderOf(stack.ipop())); 325 } 326 catch (ArithmeticException ex) 327 { 328 stack.push(valueFactory.createIntegerValue()); 329 // TODO: Forward ArithmeticExceptions. 330 //stack.clear(); 331 //stack.push(valueFactory.createReference(false)); 332 //branchUnit.throwException(); 333 } 334 break; 335 336 case InstructionConstants.OP_LREM: 337 try 338 { 339 stack.push(stack.lpop().remainderOf(stack.lpop())); 340 } 341 catch (ArithmeticException ex) 342 { 343 stack.push(valueFactory.createLongValue()); 344 // TODO: Forward ArithmeticExceptions. 345 //stack.clear(); 346 //stack.push(valueFactory.createReference(false)); 347 //branchUnit.throwException(); 348 } 349 break; 350 351 case InstructionConstants.OP_FREM: 352 stack.push(stack.fpop().remainderOf(stack.fpop())); 353 break; 354 355 case InstructionConstants.OP_DREM: 356 stack.push(stack.dpop().remainderOf(stack.dpop())); 357 break; 358 359 case InstructionConstants.OP_INEG: 360 stack.push(stack.ipop().negate()); 361 break; 362 363 case InstructionConstants.OP_LNEG: 364 stack.push(stack.lpop().negate()); 365 break; 366 367 case InstructionConstants.OP_FNEG: 368 stack.push(stack.fpop().negate()); 369 break; 370 371 case InstructionConstants.OP_DNEG: 372 stack.push(stack.dpop().negate()); 373 break; 374 375 case InstructionConstants.OP_ISHL: 376 stack.push(stack.ipop().shiftLeftOf(stack.ipop())); 377 break; 378 379 case InstructionConstants.OP_LSHL: 380 stack.push(stack.ipop().shiftLeftOf(stack.lpop())); 381 break; 382 383 case InstructionConstants.OP_ISHR: 384 stack.push(stack.ipop().shiftRightOf(stack.ipop())); 385 break; 386 387 case InstructionConstants.OP_LSHR: 388 stack.push(stack.ipop().shiftRightOf(stack.lpop())); 389 break; 390 391 case InstructionConstants.OP_IUSHR: 392 stack.push(stack.ipop().unsignedShiftRightOf(stack.ipop())); 393 break; 394 395 case InstructionConstants.OP_LUSHR: 396 stack.push(stack.ipop().unsignedShiftRightOf(stack.lpop())); 397 break; 398 399 case InstructionConstants.OP_IAND: 400 stack.push(stack.ipop().and(stack.ipop())); 401 break; 402 403 case InstructionConstants.OP_LAND: 404 stack.push(stack.lpop().and(stack.lpop())); 405 break; 406 407 case InstructionConstants.OP_IOR: 408 stack.push(stack.ipop().or(stack.ipop())); 409 break; 410 411 case InstructionConstants.OP_LOR: 412 stack.push(stack.lpop().or(stack.lpop())); 413 break; 414 415 case InstructionConstants.OP_IXOR: 416 stack.push(stack.ipop().xor(stack.ipop())); 417 break; 418 419 case InstructionConstants.OP_LXOR: 420 stack.push(stack.lpop().xor(stack.lpop())); 421 break; 422 423 case InstructionConstants.OP_I2L: 424 stack.push(stack.ipop().convertToLong()); 425 break; 426 427 case InstructionConstants.OP_I2F: 428 stack.push(stack.ipop().convertToFloat()); 429 break; 430 431 case InstructionConstants.OP_I2D: 432 stack.push(stack.ipop().convertToDouble()); 433 break; 434 435 case InstructionConstants.OP_L2I: 436 stack.push(stack.lpop().convertToInteger()); 437 break; 438 439 case InstructionConstants.OP_L2F: 440 stack.push(stack.lpop().convertToFloat()); 441 break; 442 443 case InstructionConstants.OP_L2D: 444 stack.push(stack.lpop().convertToDouble()); 445 break; 446 447 case InstructionConstants.OP_F2I: 448 stack.push(stack.fpop().convertToInteger()); 449 break; 450 451 case InstructionConstants.OP_F2L: 452 stack.push(stack.fpop().convertToLong()); 453 break; 454 455 case InstructionConstants.OP_F2D: 456 stack.push(stack.fpop().convertToDouble()); 457 break; 458 459 case InstructionConstants.OP_D2I: 460 stack.push(stack.dpop().convertToInteger()); 461 break; 462 463 case InstructionConstants.OP_D2L: 464 stack.push(stack.dpop().convertToLong()); 465 break; 466 467 case InstructionConstants.OP_D2F: 468 stack.push(stack.dpop().convertToFloat()); 469 break; 470 471 case InstructionConstants.OP_I2B: 472 stack.push(stack.ipop().convertToByte()); 473 break; 474 475 case InstructionConstants.OP_I2C: 476 stack.push(stack.ipop().convertToCharacter()); 477 break; 478 479 case InstructionConstants.OP_I2S: 480 stack.push(stack.ipop().convertToShort()); 481 break; 482 483 case InstructionConstants.OP_LCMP: 484 // stack.push(stack.lpop().compareReverse(stack.lpop())); 485 486 LongValue longValue1 = stack.lpop(); 487 LongValue longValue2 = stack.lpop(); 488 stack.push(longValue2.compare(longValue1)); 489 break; 490 491 case InstructionConstants.OP_FCMPL: 492 FloatValue floatValue1 = stack.fpop(); 493 FloatValue floatValue2 = stack.fpop(); 494 stack.push(floatValue2.compare(floatValue1)); 495 break; 496 497 case InstructionConstants.OP_FCMPG: 498 stack.push(stack.fpop().compareReverse(stack.fpop())); 499 break; 500 501 case InstructionConstants.OP_DCMPL: 502 DoubleValue doubleValue1 = stack.dpop(); 503 DoubleValue doubleValue2 = stack.dpop(); 504 stack.push(doubleValue2.compare(doubleValue1)); 505 break; 506 507 case InstructionConstants.OP_DCMPG: 508 stack.push(stack.dpop().compareReverse(stack.dpop())); 509 break; 510 511 case InstructionConstants.OP_IRETURN: 512 invocationUnit.exitMethod(clazz, method, stack.ipop()); 513 branchUnit.returnFromMethod(); 514 break; 515 516 case InstructionConstants.OP_LRETURN: 517 invocationUnit.exitMethod(clazz, method, stack.lpop()); 518 branchUnit.returnFromMethod(); 519 break; 520 521 case InstructionConstants.OP_FRETURN: 522 invocationUnit.exitMethod(clazz, method, stack.fpop()); 523 branchUnit.returnFromMethod(); 524 break; 525 526 case InstructionConstants.OP_DRETURN: 527 invocationUnit.exitMethod(clazz, method, stack.dpop()); 528 branchUnit.returnFromMethod(); 529 break; 530 531 case InstructionConstants.OP_ARETURN: 532 invocationUnit.exitMethod(clazz, method, stack.apop()); 533 branchUnit.returnFromMethod(); 534 break; 535 536 case InstructionConstants.OP_RETURN: 537 branchUnit.returnFromMethod(); 538 break; 539 540 case InstructionConstants.OP_NEWARRAY: 541 IntegerValue arrayLength = stack.ipop(); 542 stack.push(valueFactory.createArrayReferenceValue(String.valueOf(InstructionUtil.internalTypeFromArrayType((byte)simpleInstruction.constant)), 543 null, 544 arrayLength)); 545 break; 546 547 case InstructionConstants.OP_ARRAYLENGTH: 548 ReferenceValue referenceValue = stack.apop(); 549 stack.push(referenceValue.arrayLength(valueFactory)); 550 break; 551 552 case InstructionConstants.OP_ATHROW: 553 ReferenceValue exceptionReferenceValue = stack.apop(); 554 stack.clear(); 555 stack.push(exceptionReferenceValue); 556 branchUnit.throwException(); 557 break; 558 559 case InstructionConstants.OP_MONITORENTER: 560 case InstructionConstants.OP_MONITOREXIT: 561 stack.apop(); 562 break; 563 564 default: 565 throw new IllegalArgumentException("Unknown simple instruction ["+simpleInstruction.opcode+"]"); 566 } 567 } 568 569 570 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 571 { 572 int constantIndex = constantInstruction.constantIndex; 573 574 switch (constantInstruction.opcode) 575 { 576 case InstructionConstants.OP_LDC: 577 case InstructionConstants.OP_LDC_W: 578 case InstructionConstants.OP_LDC2_W: 579 stack.push(classConstantValueFactory.constantValue(clazz, constantIndex)); 580 break; 581 582 case InstructionConstants.OP_GETSTATIC: 583 case InstructionConstants.OP_PUTSTATIC: 584 case InstructionConstants.OP_GETFIELD: 585 case InstructionConstants.OP_PUTFIELD: 586 case InstructionConstants.OP_INVOKEVIRTUAL: 587 case InstructionConstants.OP_INVOKESPECIAL: 588 case InstructionConstants.OP_INVOKESTATIC: 589 case InstructionConstants.OP_INVOKEINTERFACE: 590 case InstructionConstants.OP_INVOKEDYNAMIC: 591 invocationUnit.invokeMember(clazz, method, codeAttribute, offset, constantInstruction, stack); 592 break; 593 594 case InstructionConstants.OP_NEW: 595 stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue()); 596 break; 597 598 case InstructionConstants.OP_ANEWARRAY: 599 { 600 ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue(); 601 602 stack.push(valueFactory.createArrayReferenceValue(referenceValue.internalType(), 603 referenceValue.getReferencedClass(), 604 stack.ipop())); 605 break; 606 } 607 608 case InstructionConstants.OP_CHECKCAST: 609 // TODO: Check cast. 610 ReferenceValue castValue = stack.apop(); 611 ReferenceValue castResultValue = 612 !alwaysCast && 613 castValue.isNull() == Value.ALWAYS ? castValue : 614 castValue.isNull() == Value.NEVER ? constantValueFactory.constantValue(clazz, constantIndex).referenceValue() : 615 constantValueFactory.constantValue(clazz, constantIndex).referenceValue().generalize(valueFactory.createReferenceValueNull()); 616 stack.push(castResultValue); 617 break; 618 619 case InstructionConstants.OP_INSTANCEOF: 620 { 621 ReferenceValue referenceValue = constantValueFactory.constantValue(clazz, constantIndex).referenceValue(); 622 623 int instanceOf = stack.apop().instanceOf(referenceValue.getType(), 624 referenceValue.getReferencedClass()); 625 626 stack.push(instanceOf == Value.NEVER ? valueFactory.createIntegerValue(0) : 627 instanceOf == Value.ALWAYS ? valueFactory.createIntegerValue(1) : 628 valueFactory.createIntegerValue()); 629 break; 630 } 631 632 case InstructionConstants.OP_MULTIANEWARRAY: 633 { 634 int dimensionCount = constantInstruction.constant; 635 for (int dimension = 0; dimension < dimensionCount; dimension++) 636 { 637 // TODO: Use array lengths. 638 IntegerValue arrayLength = stack.ipop(); 639 } 640 641 stack.push(constantValueFactory.constantValue(clazz, constantIndex).referenceValue()); 642 break; 643 } 644 645 default: 646 throw new IllegalArgumentException("Unknown constant pool instruction ["+constantInstruction.opcode+"]"); 647 } 648 } 649 650 651 public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 652 { 653 int variableIndex = variableInstruction.variableIndex; 654 655 switch (variableInstruction.opcode) 656 { 657 case InstructionConstants.OP_ILOAD: 658 case InstructionConstants.OP_ILOAD_0: 659 case InstructionConstants.OP_ILOAD_1: 660 case InstructionConstants.OP_ILOAD_2: 661 case InstructionConstants.OP_ILOAD_3: 662 stack.push(variables.iload(variableIndex)); 663 break; 664 665 case InstructionConstants.OP_LLOAD: 666 case InstructionConstants.OP_LLOAD_0: 667 case InstructionConstants.OP_LLOAD_1: 668 case InstructionConstants.OP_LLOAD_2: 669 case InstructionConstants.OP_LLOAD_3: 670 stack.push(variables.lload(variableIndex)); 671 break; 672 673 case InstructionConstants.OP_FLOAD: 674 case InstructionConstants.OP_FLOAD_0: 675 case InstructionConstants.OP_FLOAD_1: 676 case InstructionConstants.OP_FLOAD_2: 677 case InstructionConstants.OP_FLOAD_3: 678 stack.push(variables.fload(variableIndex)); 679 break; 680 681 case InstructionConstants.OP_DLOAD: 682 case InstructionConstants.OP_DLOAD_0: 683 case InstructionConstants.OP_DLOAD_1: 684 case InstructionConstants.OP_DLOAD_2: 685 case InstructionConstants.OP_DLOAD_3: 686 stack.push(variables.dload(variableIndex)); 687 break; 688 689 case InstructionConstants.OP_ALOAD: 690 case InstructionConstants.OP_ALOAD_0: 691 case InstructionConstants.OP_ALOAD_1: 692 case InstructionConstants.OP_ALOAD_2: 693 case InstructionConstants.OP_ALOAD_3: 694 stack.push(variables.aload(variableIndex)); 695 break; 696 697 case InstructionConstants.OP_ISTORE: 698 case InstructionConstants.OP_ISTORE_0: 699 case InstructionConstants.OP_ISTORE_1: 700 case InstructionConstants.OP_ISTORE_2: 701 case InstructionConstants.OP_ISTORE_3: 702 variables.store(variableIndex, stack.ipop()); 703 break; 704 705 case InstructionConstants.OP_LSTORE: 706 case InstructionConstants.OP_LSTORE_0: 707 case InstructionConstants.OP_LSTORE_1: 708 case InstructionConstants.OP_LSTORE_2: 709 case InstructionConstants.OP_LSTORE_3: 710 variables.store(variableIndex, stack.lpop()); 711 break; 712 713 case InstructionConstants.OP_FSTORE: 714 case InstructionConstants.OP_FSTORE_0: 715 case InstructionConstants.OP_FSTORE_1: 716 case InstructionConstants.OP_FSTORE_2: 717 case InstructionConstants.OP_FSTORE_3: 718 variables.store(variableIndex, stack.fpop()); 719 break; 720 721 case InstructionConstants.OP_DSTORE: 722 case InstructionConstants.OP_DSTORE_0: 723 case InstructionConstants.OP_DSTORE_1: 724 case InstructionConstants.OP_DSTORE_2: 725 case InstructionConstants.OP_DSTORE_3: 726 variables.store(variableIndex, stack.dpop()); 727 break; 728 729 case InstructionConstants.OP_ASTORE: 730 case InstructionConstants.OP_ASTORE_0: 731 case InstructionConstants.OP_ASTORE_1: 732 case InstructionConstants.OP_ASTORE_2: 733 case InstructionConstants.OP_ASTORE_3: 734 // The operand on the stack can be a reference or a return 735 // address, so we'll relax the pop operation. 736 //variables.store(variableIndex, stack.apop()); 737 variables.store(variableIndex, stack.pop()); 738 break; 739 740 case InstructionConstants.OP_IINC: 741 variables.store(variableIndex, 742 variables.iload(variableIndex).add( 743 valueFactory.createIntegerValue(variableInstruction.constant))); 744 break; 745 746 case InstructionConstants.OP_RET: 747 // The return address should be in the last offset of the 748 // given instruction offset variable (even though there may 749 // be other offsets). 750 InstructionOffsetValue instructionOffsetValue = variables.oload(variableIndex); 751 branchUnit.branch(clazz, 752 codeAttribute, 753 offset, 754 instructionOffsetValue.instructionOffset(instructionOffsetValue.instructionOffsetCount()-1)); 755 break; 756 757 default: 758 throw new IllegalArgumentException("Unknown variable instruction ["+variableInstruction.opcode+"]"); 759 } 760 } 761 762 763 public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 764 { 765 int branchTarget = offset + branchInstruction.branchOffset; 766 767 switch (branchInstruction.opcode) 768 { 769 case InstructionConstants.OP_IFEQ: 770 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 771 stack.ipop().equal(valueFactory.createIntegerValue(0))); 772 break; 773 774 case InstructionConstants.OP_IFNE: 775 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 776 stack.ipop().notEqual(valueFactory.createIntegerValue(0))); 777 break; 778 779 case InstructionConstants.OP_IFLT: 780 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 781 stack.ipop().lessThan(valueFactory.createIntegerValue(0))); 782 break; 783 784 case InstructionConstants.OP_IFGE: 785 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 786 stack.ipop().greaterThanOrEqual(valueFactory.createIntegerValue(0))); 787 break; 788 789 case InstructionConstants.OP_IFGT: 790 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 791 stack.ipop().greaterThan(valueFactory.createIntegerValue(0))); 792 break; 793 794 case InstructionConstants.OP_IFLE: 795 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 796 stack.ipop().lessThanOrEqual(valueFactory.createIntegerValue(0))); 797 break; 798 799 800 case InstructionConstants.OP_IFICMPEQ: 801 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 802 stack.ipop().equal(stack.ipop())); 803 break; 804 805 case InstructionConstants.OP_IFICMPNE: 806 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 807 stack.ipop().notEqual(stack.ipop())); 808 break; 809 810 case InstructionConstants.OP_IFICMPLT: 811 // Note that the stack entries are popped in reverse order. 812 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 813 stack.ipop().greaterThan(stack.ipop())); 814 break; 815 816 case InstructionConstants.OP_IFICMPGE: 817 // Note that the stack entries are popped in reverse order. 818 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 819 stack.ipop().lessThanOrEqual(stack.ipop())); 820 break; 821 822 case InstructionConstants.OP_IFICMPGT: 823 // Note that the stack entries are popped in reverse order. 824 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 825 stack.ipop().lessThan(stack.ipop())); 826 break; 827 828 case InstructionConstants.OP_IFICMPLE: 829 // Note that the stack entries are popped in reverse order. 830 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 831 stack.ipop().greaterThanOrEqual(stack.ipop())); 832 break; 833 834 case InstructionConstants.OP_IFACMPEQ: 835 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 836 stack.apop().equal(stack.apop())); 837 break; 838 839 case InstructionConstants.OP_IFACMPNE: 840 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 841 stack.apop().notEqual(stack.apop())); 842 break; 843 844 case InstructionConstants.OP_GOTO: 845 case InstructionConstants.OP_GOTO_W: 846 branchUnit.branch(clazz, codeAttribute, offset, branchTarget); 847 break; 848 849 850 case InstructionConstants.OP_JSR: 851 case InstructionConstants.OP_JSR_W: 852 stack.push(new InstructionOffsetValue(offset + 853 branchInstruction.length(offset))); 854 branchUnit.branch(clazz, codeAttribute, offset, branchTarget); 855 break; 856 857 case InstructionConstants.OP_IFNULL: 858 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 859 stack.apop().isNull()); 860 break; 861 862 case InstructionConstants.OP_IFNONNULL: 863 branchUnit.branchConditionally(clazz, codeAttribute, offset, branchTarget, 864 stack.apop().isNotNull()); 865 break; 866 867 default: 868 throw new IllegalArgumentException("Unknown branch instruction ["+branchInstruction.opcode+"]"); 869 } 870 } 871 872 873 public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) 874 { 875 IntegerValue indexValue = stack.ipop(); 876 877 // If there is no definite branch in any of the cases below, 878 // branch to the default offset. 879 branchUnit.branch(clazz, codeAttribute, 880 offset, 881 offset + tableSwitchInstruction.defaultOffset); 882 883 for (int index = 0; index < tableSwitchInstruction.jumpOffsets.length; index++) 884 { 885 int conditional = indexValue.equal(valueFactory.createIntegerValue( 886 tableSwitchInstruction.lowCase + index)); 887 branchUnit.branchConditionally(clazz, codeAttribute, 888 offset, 889 offset + tableSwitchInstruction.jumpOffsets[index], 890 conditional); 891 892 // If this branch is always taken, we can skip the rest. 893 if (conditional == Value.ALWAYS) 894 { 895 break; 896 } 897 } 898 } 899 900 901 public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) 902 { 903 IntegerValue indexValue = stack.ipop(); 904 905 // If there is no definite branch in any of the cases below, 906 // branch to the default offset. 907 branchUnit.branch(clazz, codeAttribute, 908 offset, 909 offset + lookUpSwitchInstruction.defaultOffset); 910 911 for (int index = 0; index < lookUpSwitchInstruction.jumpOffsets.length; index++) 912 { 913 int conditional = indexValue.equal(valueFactory.createIntegerValue( 914 lookUpSwitchInstruction.cases[index])); 915 branchUnit.branchConditionally(clazz, codeAttribute, 916 offset, 917 offset + lookUpSwitchInstruction.jumpOffsets[index], 918 conditional); 919 920 // If this branch is always taken, we can skip the rest. 921 if (conditional == Value.ALWAYS) 922 { 923 break; 924 } 925 } 926 } 927 } 928