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 */ 21 package proguard.classfile.instruction; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.CodeAttribute; 25 import proguard.classfile.instruction.visitor.InstructionVisitor; 26 27 /** 28 * Base class for representing instructions. 29 * 30 * @author Eric Lafortune 31 */ 32 public abstract class Instruction 33 { 34 // An array for marking Category 2 instructions. 35 private static final boolean[] IS_CATEGORY2 = new boolean[] 36 { 37 false, // nop 38 false, // aconst_null 39 false, // iconst_m1 40 false, // iconst_0 41 false, // iconst_1 42 false, // iconst_2 43 false, // iconst_3 44 false, // iconst_4 45 false, // iconst_5 46 true, // lconst_0 47 true, // lconst_1 48 false, // fconst_0 49 false, // fconst_1 50 false, // fconst_2 51 true, // dconst_0 52 true, // dconst_1 53 false, // bipush 54 false, // sipush 55 false, // ldc 56 false, // ldc_w 57 true, // ldc2_w 58 false, // iload 59 true, // lload 60 false, // fload 61 true, // dload 62 false, // aload 63 false, // iload_0 64 false, // iload_1 65 false, // iload_2 66 false, // iload_3 67 true, // lload_0 68 true, // lload_1 69 true, // lload_2 70 true, // lload_3 71 false, // fload_0 72 false, // fload_1 73 false, // fload_2 74 false, // fload_3 75 true, // dload_0 76 true, // dload_1 77 true, // dload_2 78 true, // dload_3 79 false, // aload_0 80 false, // aload_1 81 false, // aload_2 82 false, // aload_3 83 false, // iaload 84 true, // laload 85 false, // faload 86 true, // daload 87 false, // aaload 88 false, // baload 89 false, // caload 90 false, // saload 91 false, // istore 92 true, // lstore 93 false, // fstore 94 true, // dstore 95 false, // astore 96 false, // istore_0 97 false, // istore_1 98 false, // istore_2 99 false, // istore_3 100 true, // lstore_0 101 true, // lstore_1 102 true, // lstore_2 103 true, // lstore_3 104 false, // fstore_0 105 false, // fstore_1 106 false, // fstore_2 107 false, // fstore_3 108 true, // dstore_0 109 true, // dstore_1 110 true, // dstore_2 111 true, // dstore_3 112 false, // astore_0 113 false, // astore_1 114 false, // astore_2 115 false, // astore_3 116 false, // iastore 117 true, // lastore 118 false, // fastore 119 true, // dastore 120 false, // aastore 121 false, // bastore 122 false, // castore 123 false, // sastore 124 false, // pop 125 true, // pop2 126 false, // dup 127 false, // dup_x1 128 false, // dup_x2 129 true, // dup2 130 true, // dup2_x1 131 true, // dup2_x2 132 false, // swap 133 false, // iadd 134 true, // ladd 135 false, // fadd 136 true, // dadd 137 false, // isub 138 true, // lsub 139 false, // fsub 140 true, // dsub 141 false, // imul 142 true, // lmul 143 false, // fmul 144 true, // dmul 145 false, // idiv 146 true, // ldiv 147 false, // fdiv 148 true, // ddiv 149 false, // irem 150 true, // lrem 151 false, // frem 152 true, // drem 153 false, // ineg 154 true, // lneg 155 false, // fneg 156 true, // dneg 157 false, // ishl 158 true, // lshl 159 false, // ishr 160 true, // lshr 161 false, // iushr 162 true, // lushr 163 false, // iand 164 true, // land 165 false, // ior 166 true, // lor 167 false, // ixor 168 true, // lxor 169 false, // iinc 170 false, // i2l 171 false, // i2f 172 false, // i2d 173 true, // l2i 174 true, // l2f 175 true, // l2d 176 false, // f2i 177 false, // f2l 178 false, // f2d 179 true, // d2i 180 true, // d2l 181 true, // d2f 182 false, // i2b 183 false, // i2c 184 false, // i2s 185 true, // lcmp 186 false, // fcmpl 187 false, // fcmpg 188 true, // dcmpl 189 true, // dcmpg 190 false, // ifeq 191 false, // ifne 192 false, // iflt 193 false, // ifge 194 false, // ifgt 195 false, // ifle 196 false, // ificmpeq 197 false, // ificmpne 198 false, // ificmplt 199 false, // ificmpge 200 false, // ificmpgt 201 false, // ificmple 202 false, // ifacmpeq 203 false, // ifacmpne 204 false, // goto 205 false, // jsr 206 false, // ret 207 false, // tableswitch 208 false, // lookupswitch 209 false, // ireturn 210 true, // lreturn 211 false, // freturn 212 true, // dreturn 213 false, // areturn 214 false, // return 215 false, // getstatic 216 false, // putstatic 217 false, // getfield 218 false, // putfield 219 false, // invokevirtual 220 false, // invokespecial 221 false, // invokestatic 222 false, // invokeinterface 223 false, // invokedynamic 224 false, // new 225 false, // newarray 226 false, // anewarray 227 false, // arraylength 228 false, // athrow 229 false, // checkcast 230 false, // instanceof 231 false, // monitorenter 232 false, // monitorexit 233 false, // wide 234 false, // multianewarray 235 false, // ifnull 236 false, // ifnonnull 237 false, // goto_w 238 false, // jsr_w 239 }; 240 241 242 // An array containing the fixed number of entries popped from the stack, 243 // for all instructions. 244 private static final int[] STACK_POP_COUNTS = new int[] 245 { 246 0, // nop 247 0, // aconst_null 248 0, // iconst_m1 249 0, // iconst_0 250 0, // iconst_1 251 0, // iconst_2 252 0, // iconst_3 253 0, // iconst_4 254 0, // iconst_5 255 0, // lconst_0 256 0, // lconst_1 257 0, // fconst_0 258 0, // fconst_1 259 0, // fconst_2 260 0, // dconst_0 261 0, // dconst_1 262 0, // bipush 263 0, // sipush 264 0, // ldc 265 0, // ldc_w 266 0, // ldc2_w 267 0, // iload 268 0, // lload 269 0, // fload 270 0, // dload 271 0, // aload 272 0, // iload_0 273 0, // iload_1 274 0, // iload_2 275 0, // iload_3 276 0, // lload_0 277 0, // lload_1 278 0, // lload_2 279 0, // lload_3 280 0, // fload_0 281 0, // fload_1 282 0, // fload_2 283 0, // fload_3 284 0, // dload_0 285 0, // dload_1 286 0, // dload_2 287 0, // dload_3 288 0, // aload_0 289 0, // aload_1 290 0, // aload_2 291 0, // aload_3 292 2, // iaload 293 2, // laload 294 2, // faload 295 2, // daload 296 2, // aaload 297 2, // baload 298 2, // caload 299 2, // saload 300 1, // istore 301 2, // lstore 302 1, // fstore 303 2, // dstore 304 1, // astore 305 1, // istore_0 306 1, // istore_1 307 1, // istore_2 308 1, // istore_3 309 2, // lstore_0 310 2, // lstore_1 311 2, // lstore_2 312 2, // lstore_3 313 1, // fstore_0 314 1, // fstore_1 315 1, // fstore_2 316 1, // fstore_3 317 2, // dstore_0 318 2, // dstore_1 319 2, // dstore_2 320 2, // dstore_3 321 1, // astore_0 322 1, // astore_1 323 1, // astore_2 324 1, // astore_3 325 3, // iastore 326 4, // lastore 327 3, // fastore 328 4, // dastore 329 3, // aastore 330 3, // bastore 331 3, // castore 332 3, // sastore 333 1, // pop 334 2, // pop2 335 1, // dup 336 2, // dup_x1 337 3, // dup_x2 338 2, // dup2 339 3, // dup2_x1 340 4, // dup2_x2 341 2, // swap 342 2, // iadd 343 4, // ladd 344 2, // fadd 345 4, // dadd 346 2, // isub 347 4, // lsub 348 2, // fsub 349 4, // dsub 350 2, // imul 351 4, // lmul 352 2, // fmul 353 4, // dmul 354 2, // idiv 355 4, // ldiv 356 2, // fdiv 357 4, // ddiv 358 2, // irem 359 4, // lrem 360 2, // frem 361 4, // drem 362 1, // ineg 363 2, // lneg 364 1, // fneg 365 2, // dneg 366 2, // ishl 367 3, // lshl 368 2, // ishr 369 3, // lshr 370 2, // iushr 371 3, // lushr 372 2, // iand 373 4, // land 374 2, // ior 375 4, // lor 376 2, // ixor 377 4, // lxor 378 0, // iinc 379 1, // i2l 380 1, // i2f 381 1, // i2d 382 2, // l2i 383 2, // l2f 384 2, // l2d 385 1, // f2i 386 1, // f2l 387 1, // f2d 388 2, // d2i 389 2, // d2l 390 2, // d2f 391 1, // i2b 392 1, // i2c 393 1, // i2s 394 4, // lcmp 395 2, // fcmpl 396 2, // fcmpg 397 4, // dcmpl 398 4, // dcmpg 399 1, // ifeq 400 1, // ifne 401 1, // iflt 402 1, // ifge 403 1, // ifgt 404 1, // ifle 405 2, // ificmpeq 406 2, // ificmpne 407 2, // ificmplt 408 2, // ificmpge 409 2, // ificmpgt 410 2, // ificmple 411 2, // ifacmpeq 412 2, // ifacmpne 413 0, // goto 414 0, // jsr 415 0, // ret 416 1, // tableswitch 417 1, // lookupswitch 418 1, // ireturn 419 2, // lreturn 420 1, // freturn 421 2, // dreturn 422 1, // areturn 423 0, // return 424 0, // getstatic 425 0, // putstatic 426 1, // getfield 427 1, // putfield 428 1, // invokevirtual 429 1, // invokespecial 430 0, // invokestatic 431 1, // invokeinterface 432 0, // invokedynamic 433 0, // new 434 1, // newarray 435 1, // anewarray 436 1, // arraylength 437 1, // athrow 438 1, // checkcast 439 1, // instanceof 440 1, // monitorenter 441 1, // monitorexit 442 0, // wide 443 0, // multianewarray 444 1, // ifnull 445 1, // ifnonnull 446 0, // goto_w 447 0, // jsr_w 448 }; 449 450 451 // An array containing the fixed number of entries pushed onto the stack, 452 // for all instructions. 453 private static final int[] STACK_PUSH_COUNTS = new int[] 454 { 455 0, // nop 456 1, // aconst_null 457 1, // iconst_m1 458 1, // iconst_0 459 1, // iconst_1 460 1, // iconst_2 461 1, // iconst_3 462 1, // iconst_4 463 1, // iconst_5 464 2, // lconst_0 465 2, // lconst_1 466 1, // fconst_0 467 1, // fconst_1 468 1, // fconst_2 469 2, // dconst_0 470 2, // dconst_1 471 1, // bipush 472 1, // sipush 473 1, // ldc 474 1, // ldc_w 475 2, // ldc2_w 476 1, // iload 477 2, // lload 478 1, // fload 479 2, // dload 480 1, // aload 481 1, // iload_0 482 1, // iload_1 483 1, // iload_2 484 1, // iload_3 485 2, // lload_0 486 2, // lload_1 487 2, // lload_2 488 2, // lload_3 489 1, // fload_0 490 1, // fload_1 491 1, // fload_2 492 1, // fload_3 493 2, // dload_0 494 2, // dload_1 495 2, // dload_2 496 2, // dload_3 497 1, // aload_0 498 1, // aload_1 499 1, // aload_2 500 1, // aload_3 501 1, // iaload 502 2, // laload 503 1, // faload 504 2, // daload 505 1, // aaload 506 1, // baload 507 1, // caload 508 1, // saload 509 0, // istore 510 0, // lstore 511 0, // fstore 512 0, // dstore 513 0, // astore 514 0, // istore_0 515 0, // istore_1 516 0, // istore_2 517 0, // istore_3 518 0, // lstore_0 519 0, // lstore_1 520 0, // lstore_2 521 0, // lstore_3 522 0, // fstore_0 523 0, // fstore_1 524 0, // fstore_2 525 0, // fstore_3 526 0, // dstore_0 527 0, // dstore_1 528 0, // dstore_2 529 0, // dstore_3 530 0, // astore_0 531 0, // astore_1 532 0, // astore_2 533 0, // astore_3 534 0, // iastore 535 0, // lastore 536 0, // fastore 537 0, // dastore 538 0, // aastore 539 0, // bastore 540 0, // castore 541 0, // sastore 542 0, // pop 543 0, // pop2 544 2, // dup 545 3, // dup_x1 546 4, // dup_x2 547 4, // dup2 548 5, // dup2_x1 549 6, // dup2_x2 550 2, // swap 551 1, // iadd 552 2, // ladd 553 1, // fadd 554 2, // dadd 555 1, // isub 556 2, // lsub 557 1, // fsub 558 2, // dsub 559 1, // imul 560 2, // lmul 561 1, // fmul 562 2, // dmul 563 1, // idiv 564 2, // ldiv 565 1, // fdiv 566 2, // ddiv 567 1, // irem 568 2, // lrem 569 1, // frem 570 2, // drem 571 1, // ineg 572 2, // lneg 573 1, // fneg 574 2, // dneg 575 1, // ishl 576 2, // lshl 577 1, // ishr 578 2, // lshr 579 1, // iushr 580 2, // lushr 581 1, // iand 582 2, // land 583 1, // ior 584 2, // lor 585 1, // ixor 586 2, // lxor 587 0, // iinc 588 2, // i2l 589 1, // i2f 590 2, // i2d 591 1, // l2i 592 1, // l2f 593 2, // l2d 594 1, // f2i 595 2, // f2l 596 2, // f2d 597 1, // d2i 598 2, // d2l 599 1, // d2f 600 1, // i2b 601 1, // i2c 602 1, // i2s 603 1, // lcmp 604 1, // fcmpl 605 1, // fcmpg 606 1, // dcmpl 607 1, // dcmpg 608 0, // ifeq 609 0, // ifne 610 0, // iflt 611 0, // ifge 612 0, // ifgt 613 0, // ifle 614 0, // ificmpeq 615 0, // ificmpne 616 0, // ificmplt 617 0, // ificmpge 618 0, // ificmpgt 619 0, // ificmple 620 0, // ifacmpeq 621 0, // ifacmpne 622 0, // goto 623 1, // jsr 624 0, // ret 625 0, // tableswitch 626 0, // lookupswitch 627 0, // ireturn 628 0, // lreturn 629 0, // freturn 630 0, // dreturn 631 0, // areturn 632 0, // return 633 0, // getstatic 634 0, // putstatic 635 0, // getfield 636 0, // putfield 637 0, // invokevirtual 638 0, // invokespecial 639 0, // invokestatic 640 0, // invokeinterface 641 0, // invokedynamic 642 1, // new 643 1, // newarray 644 1, // anewarray 645 1, // arraylength 646 0, // athrow 647 1, // checkcast 648 1, // instanceof 649 0, // monitorenter 650 0, // monitorexit 651 0, // wide 652 1, // multianewarray 653 0, // ifnull 654 0, // ifnonnull 655 0, // goto_w 656 1, // jsr_w 657 }; 658 659 660 public byte opcode; 661 662 663 /** 664 * Returns the canonical opcode of this instruction, i.e. typically the 665 * opcode whose extension has been removed. 666 */ canonicalOpcode()667 public byte canonicalOpcode() 668 { 669 return opcode; 670 } 671 672 673 /** 674 * Shrinks this instruction to its shortest possible form. 675 * @return this instruction. 676 */ shrink()677 public abstract Instruction shrink(); 678 679 680 681 /** 682 * Writes the Instruction at the given offset in the given code attribute. 683 */ write(CodeAttribute codeAttribute, int offset)684 public final void write(CodeAttribute codeAttribute, int offset) 685 { 686 write(codeAttribute.code, offset); 687 } 688 689 690 /** 691 * Writes the Instruction at the given offset in the given code array. 692 */ write(byte[] code, int offset)693 public void write(byte[] code, int offset) 694 { 695 // Write the wide opcode, if necessary. 696 if (isWide()) 697 { 698 code[offset++] = InstructionConstants.OP_WIDE; 699 } 700 701 // Write the opcode. 702 code[offset++] = opcode; 703 704 // Write any additional arguments. 705 writeInfo(code, offset); 706 } 707 708 709 /** 710 * Returns whether the instruction is wide, i.e. preceded by a wide opcode. 711 * With the current specifications, only variable instructions can be wide. 712 */ isWide()713 protected boolean isWide() 714 { 715 return false; 716 } 717 718 719 /** 720 * Reads the data following the instruction opcode. 721 */ readInfo(byte[] code, int offset)722 protected abstract void readInfo(byte[] code, int offset); 723 724 725 /** 726 * Writes data following the instruction opcode. 727 */ writeInfo(byte[] code, int offset)728 protected abstract void writeInfo(byte[] code, int offset); 729 730 731 /** 732 * Returns the length in bytes of the instruction. 733 */ length(int offset)734 public abstract int length(int offset); 735 736 737 /** 738 * Accepts the given visitor. 739 */ accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)740 public abstract void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor); 741 742 743 /** 744 * Returns a description of the instruction, at the given offset. 745 */ toString(int offset)746 public String toString(int offset) 747 { 748 return "["+offset+"] "+ this.toString(); 749 } 750 751 752 /** 753 * Returns the name of the instruction. 754 */ getName()755 public String getName() 756 { 757 return InstructionConstants.NAMES[opcode & 0xff]; 758 } 759 760 761 /** 762 * Returns whether the instruction is a Category 2 instruction. This means 763 * that it operates on long or double arguments. 764 */ isCategory2()765 public boolean isCategory2() 766 { 767 return IS_CATEGORY2[opcode & 0xff]; 768 } 769 770 771 /** 772 * Returns the number of entries popped from the stack during the execution 773 * of the instruction. 774 */ stackPopCount(Clazz clazz)775 public int stackPopCount(Clazz clazz) 776 { 777 return STACK_POP_COUNTS[opcode & 0xff]; 778 } 779 780 781 /** 782 * Returns the number of entries pushed onto the stack during the execution 783 * of the instruction. 784 */ stackPushCount(Clazz clazz)785 public int stackPushCount(Clazz clazz) 786 { 787 return STACK_PUSH_COUNTS[opcode & 0xff]; 788 } 789 790 791 // Small utility methods. 792 readByte(byte[] code, int offset)793 protected static int readByte(byte[] code, int offset) 794 { 795 return code[offset] & 0xff; 796 } 797 readShort(byte[] code, int offset)798 protected static int readShort(byte[] code, int offset) 799 { 800 return ((code[offset++] & 0xff) << 8) | 801 ( code[offset ] & 0xff ); 802 } 803 readInt(byte[] code, int offset)804 protected static int readInt(byte[] code, int offset) 805 { 806 return ( code[offset++] << 24) | 807 ((code[offset++] & 0xff) << 16) | 808 ((code[offset++] & 0xff) << 8) | 809 ( code[offset ] & 0xff ); 810 } 811 readValue(byte[] code, int offset, int valueSize)812 protected static int readValue(byte[] code, int offset, int valueSize) 813 { 814 switch (valueSize) 815 { 816 case 0: return 0; 817 case 1: return readByte( code, offset); 818 case 2: return readShort(code, offset); 819 case 4: return readInt( code, offset); 820 default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); 821 } 822 } 823 readSignedByte(byte[] code, int offset)824 protected static int readSignedByte(byte[] code, int offset) 825 { 826 return code[offset]; 827 } 828 readSignedShort(byte[] code, int offset)829 protected static int readSignedShort(byte[] code, int offset) 830 { 831 return (code[offset++] << 8) | 832 (code[offset ] & 0xff); 833 } 834 readSignedValue(byte[] code, int offset, int valueSize)835 protected static int readSignedValue(byte[] code, int offset, int valueSize) 836 { 837 switch (valueSize) 838 { 839 case 0: return 0; 840 case 1: return readSignedByte( code, offset); 841 case 2: return readSignedShort(code, offset); 842 case 4: return readInt( code, offset); 843 default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); 844 } 845 } 846 writeByte(byte[] code, int offset, int value)847 protected static void writeByte(byte[] code, int offset, int value) 848 { 849 if (value > 0xff) 850 { 851 throw new IllegalArgumentException("Unsigned byte value larger than 0xff ["+value+"]"); 852 } 853 854 code[offset] = (byte)value; 855 } 856 writeShort(byte[] code, int offset, int value)857 protected static void writeShort(byte[] code, int offset, int value) 858 { 859 if (value > 0xffff) 860 { 861 throw new IllegalArgumentException("Unsigned short value larger than 0xffff ["+value+"]"); 862 } 863 864 code[offset++] = (byte)(value >> 8); 865 code[offset ] = (byte)(value ); 866 } 867 writeInt(byte[] code, int offset, int value)868 protected static void writeInt(byte[] code, int offset, int value) 869 { 870 code[offset++] = (byte)(value >> 24); 871 code[offset++] = (byte)(value >> 16); 872 code[offset++] = (byte)(value >> 8); 873 code[offset ] = (byte)(value ); 874 } 875 writeValue(byte[] code, int offset, int value, int valueSize)876 protected static void writeValue(byte[] code, int offset, int value, int valueSize) 877 { 878 switch (valueSize) 879 { 880 case 0: break; 881 case 1: writeByte( code, offset, value); break; 882 case 2: writeShort(code, offset, value); break; 883 case 4: writeInt( code, offset, value); break; 884 default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); 885 } 886 } 887 writeSignedByte(byte[] code, int offset, int value)888 protected static void writeSignedByte(byte[] code, int offset, int value) 889 { 890 if ((byte)value != value) 891 { 892 throw new IllegalArgumentException("Signed byte value out of range ["+value+"]"); 893 } 894 895 code[offset] = (byte)value; 896 } 897 writeSignedShort(byte[] code, int offset, int value)898 protected static void writeSignedShort(byte[] code, int offset, int value) 899 { 900 if ((short)value != value) 901 { 902 throw new IllegalArgumentException("Signed short value out of range ["+value+"]"); 903 } 904 905 code[offset++] = (byte)(value >> 8); 906 code[offset ] = (byte)(value ); 907 } 908 writeSignedValue(byte[] code, int offset, int value, int valueSize)909 protected static void writeSignedValue(byte[] code, int offset, int value, int valueSize) 910 { 911 switch (valueSize) 912 { 913 case 0: break; 914 case 1: writeSignedByte( code, offset, value); break; 915 case 2: writeSignedShort(code, offset, value); break; 916 case 4: writeInt( code, offset, value); break; 917 default: throw new IllegalArgumentException("Unsupported value size ["+valueSize+"]"); 918 } 919 } 920 } 921