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