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