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