1 21 22 package org.apache.derby.impl.services.bytecode; 23 24 import org.apache.derby.iapi.services.classfile.CONSTANT_Index_info; 25 import org.apache.derby.iapi.services.classfile.CONSTANT_Utf8_info; 26 import org.apache.derby.iapi.services.classfile.ClassFormatOutput; 27 import org.apache.derby.iapi.services.classfile.ClassHolder; 28 import org.apache.derby.iapi.services.classfile.ClassMember; 29 import org.apache.derby.iapi.services.classfile.VMDescriptor; 30 31 import org.apache.derby.iapi.services.sanity.SanityManager; 32 import org.apache.derby.iapi.services.classfile.VMOpcode; 33 import org.apache.derby.iapi.services.io.ArrayOutputStream; 34 35 import java.io.IOException ; 36 import java.lang.reflect.Modifier ; 37 import java.util.Arrays ; 38 39 48 final class CodeChunk { 49 50 53 private static final int CODE_OFFSET = 8; 54 55 static final short[] LOAD_VARIABLE = { 60 VMOpcode.ILOAD, 61 VMOpcode.ILOAD, 62 VMOpcode.ILOAD, 63 VMOpcode.LLOAD, 64 VMOpcode.FLOAD, 65 VMOpcode.DLOAD, 66 VMOpcode.ILOAD, 67 VMOpcode.ALOAD 68 }; 69 70 static final short[] LOAD_VARIABLE_FAST = { 71 VMOpcode.ILOAD_0, 72 VMOpcode.ILOAD_0, 73 VMOpcode.ILOAD_0, 74 VMOpcode.LLOAD_0, 75 VMOpcode.FLOAD_0, 76 VMOpcode.DLOAD_0, 77 VMOpcode.ILOAD_0, 78 VMOpcode.ALOAD_0 79 }; 80 81 static final short[] STORE_VARIABLE = { 86 VMOpcode.ISTORE, 87 VMOpcode.ISTORE, 88 VMOpcode.ISTORE, 89 VMOpcode.LSTORE, 90 VMOpcode.FSTORE, 91 VMOpcode.DSTORE, 92 VMOpcode.ISTORE, 93 VMOpcode.ASTORE 94 }; 95 96 static final short[] STORE_VARIABLE_FAST = { 97 VMOpcode.ISTORE_0, 98 VMOpcode.ISTORE_0, 99 VMOpcode.ISTORE_0, 100 VMOpcode.LSTORE_0, 101 VMOpcode.FSTORE_0, 102 VMOpcode.DSTORE_0, 103 VMOpcode.ISTORE_0, 104 VMOpcode.ASTORE_0 105 }; 106 107 static final short ARRAY_ACCESS[] = { 108 VMOpcode.BALOAD, 109 VMOpcode.SALOAD, 110 VMOpcode.IALOAD, 111 VMOpcode.LALOAD, 112 VMOpcode.FALOAD, 113 VMOpcode.DALOAD, 114 VMOpcode.CALOAD, 115 VMOpcode.AALOAD 116 }; 117 static final short ARRAY_STORE[] = { 118 VMOpcode.BASTORE, 119 VMOpcode.SASTORE, 120 VMOpcode.IASTORE, 121 VMOpcode.LASTORE, 122 VMOpcode.FASTORE, 123 VMOpcode.DASTORE, 124 VMOpcode.CASTORE, 125 VMOpcode.AASTORE 126 }; 127 static final short[] RETURN_OPCODE = { 128 VMOpcode.IRETURN, 129 VMOpcode.IRETURN, 130 VMOpcode.IRETURN, 131 VMOpcode.LRETURN, 132 VMOpcode.FRETURN, 133 VMOpcode.DRETURN, 134 VMOpcode.IRETURN, 135 VMOpcode.ARETURN 136 }; 137 138 149 static final short CAST_CONVERSION_INFO[][][] = { 150 151 { 152 { VMOpcode.NOP, BCExpr.vm_byte }, 153 { VMOpcode.NOP, BCExpr.vm_short }, 154 { VMOpcode.NOP, BCExpr.vm_int }, 155 { VMOpcode.NOP, BCExpr.vm_int }, 156 { VMOpcode.NOP, BCExpr.vm_int }, 157 { VMOpcode.NOP, BCExpr.vm_int }, 158 { VMOpcode.NOP, BCExpr.vm_char }, 159 { VMOpcode.BAD, BCExpr.vm_reference } 160 }, 161 162 { 163 { VMOpcode.NOP, BCExpr.vm_byte }, 164 { VMOpcode.NOP, BCExpr.vm_short }, 165 { VMOpcode.NOP, BCExpr.vm_int }, 166 { VMOpcode.NOP, BCExpr.vm_int }, 167 { VMOpcode.NOP, BCExpr.vm_int }, 168 { VMOpcode.NOP, BCExpr.vm_int }, 169 { VMOpcode.NOP, BCExpr.vm_char }, 170 { VMOpcode.BAD, BCExpr.vm_reference } 171 }, 172 173 { 174 { VMOpcode.I2B, BCExpr.vm_byte }, 175 { VMOpcode.I2S, BCExpr.vm_short }, 176 { VMOpcode.NOP, BCExpr.vm_int }, 177 { VMOpcode.I2L, BCExpr.vm_long }, 178 { VMOpcode.I2F, BCExpr.vm_float }, 179 { VMOpcode.I2D, BCExpr.vm_double }, 180 { VMOpcode.I2B, BCExpr.vm_char }, 181 { VMOpcode.BAD, BCExpr.vm_reference } 182 }, 183 184 { 185 { VMOpcode.L2I, BCExpr.vm_int }, 186 { VMOpcode.L2I, BCExpr.vm_int }, 187 { VMOpcode.L2I, BCExpr.vm_int }, 188 { VMOpcode.NOP, BCExpr.vm_long }, 189 { VMOpcode.L2F, BCExpr.vm_float }, 190 { VMOpcode.L2D, BCExpr.vm_double }, 191 { VMOpcode.L2I, BCExpr.vm_int }, 192 { VMOpcode.BAD, BCExpr.vm_reference } 193 }, 194 195 { 196 { VMOpcode.F2I, BCExpr.vm_int }, 197 { VMOpcode.F2I, BCExpr.vm_int }, 198 { VMOpcode.F2I, BCExpr.vm_int }, 199 { VMOpcode.F2L, BCExpr.vm_long }, 200 { VMOpcode.NOP, BCExpr.vm_float }, 201 { VMOpcode.F2D, BCExpr.vm_double }, 202 { VMOpcode.F2I, BCExpr.vm_int }, 203 { VMOpcode.BAD, BCExpr.vm_reference } 204 }, 205 206 { 207 { VMOpcode.D2I, BCExpr.vm_int }, 208 { VMOpcode.D2I, BCExpr.vm_int }, 209 { VMOpcode.D2I, BCExpr.vm_int }, 210 { VMOpcode.D2L, BCExpr.vm_long }, 211 { VMOpcode.D2F, BCExpr.vm_float }, 212 { VMOpcode.NOP, BCExpr.vm_double }, 213 { VMOpcode.D2I, BCExpr.vm_int }, 214 { VMOpcode.BAD, BCExpr.vm_reference } 215 }, 216 217 { 218 { VMOpcode.NOP, BCExpr.vm_byte }, 219 { VMOpcode.NOP, BCExpr.vm_short }, 220 { VMOpcode.NOP, BCExpr.vm_int }, 221 { VMOpcode.NOP, BCExpr.vm_int }, 222 { VMOpcode.NOP, BCExpr.vm_int }, 223 { VMOpcode.NOP, BCExpr.vm_int }, 224 { VMOpcode.NOP, BCExpr.vm_char }, 225 { VMOpcode.BAD, BCExpr.vm_reference } 226 }, 227 228 { 229 { VMOpcode.BAD, BCExpr.vm_byte }, 230 { VMOpcode.BAD, BCExpr.vm_short }, 231 { VMOpcode.BAD, BCExpr.vm_int }, 232 { VMOpcode.BAD, BCExpr.vm_long }, 233 { VMOpcode.BAD, BCExpr.vm_float }, 234 { VMOpcode.BAD, BCExpr.vm_double }, 235 { VMOpcode.BAD, BCExpr.vm_char }, 236 { VMOpcode.NOP, BCExpr.vm_reference } 237 } 238 }; 239 240 245 private static final byte[] push1_1i = {1, 1}; 246 247 252 private static final byte[] push2_1i = {2, 1}; 253 257 private static final byte[] NS = {0, -1}; 258 259 260 264 private static final byte VARIABLE_STACK = -128; 265 266 279 private static final byte[][] OPCODE_ACTION = 280 { 281 282 { 0, 1 }, 283 284 push1_1i, 285 push1_1i, 286 push1_1i, 287 push1_1i, 288 push1_1i, 289 push1_1i, 290 push1_1i, 291 push1_1i, 292 push2_1i, 293 push2_1i, 294 push1_1i, 295 push1_1i, 296 push1_1i, 297 push2_1i, 298 push2_1i, 299 300 {1, 2}, 301 {1, 3}, 302 {1, 2}, 303 {1, 3}, 304 {2, 3}, 305 306 { 1, 2 }, 307 { 2, 2 }, 308 { 1, 2 }, 309 { 2, 2 }, 310 { 1, 2 }, 311 push1_1i, 312 push1_1i, 313 push1_1i, 314 push1_1i, 315 push2_1i, 316 push2_1i, 317 push2_1i, 318 push2_1i, 319 push1_1i, 320 push1_1i, 321 push1_1i, 322 push1_1i, 323 push2_1i, 324 push2_1i, 325 push2_1i, 326 push2_1i, 327 push1_1i, 328 push1_1i, 329 push1_1i, 330 push1_1i, 331 { -1, 1 }, 332 { 0, 1 }, 333 { -1, 1 }, 334 { 0, 1 }, 335 { -1, 1 }, 336 { -1, 1 }, 337 { -1, 1 }, 338 339 { -1, 1 }, 340 { -1, 2 }, 341 { -2, 2 }, 342 { -1, 2 }, 343 { -2, 2 }, 344 { -1, 2 }, 345 { -1, 1 }, 346 { -1, 1 }, 347 { -1, 1 }, 348 { -1, 1 }, 349 { -2, 1 }, 350 { -2, 1 }, 351 { -2, 1 }, 352 { -2, 1 }, 353 { -1, 1 }, 354 { -1, 1 }, 355 { -1, 1 }, 356 { -1, 1 }, 357 { -2, 1 }, 358 { -2, 1 }, 359 { -2, 1 }, 360 { -2, 1 }, 361 { -1, 1 }, 362 { -1, 1 }, 363 { -1, 1 }, 364 { -1, 1 }, 365 { -3, 1 }, 366 { -4, 1 }, 367 { -3, 1 }, 368 { -4, 1 }, 369 { -3, 1 }, 370 { -3, 1 }, 371 { -3, 1 }, 372 { -3, 1 }, 373 374 { -1, 1 }, 375 { -2, 1 }, 376 push1_1i, 377 push1_1i, 378 push1_1i, 379 push2_1i, 380 push2_1i, 381 push2_1i, 382 { 0, 1 }, 383 384 NS, 385 NS, 386 { -1, 1 }, 387 { -2, 1 }, 388 NS, 389 NS, 390 { -1, 1 }, 391 { -2, 1 }, 392 NS, 393 NS, 394 { -1, 1 }, 395 { -2, 1 }, 396 NS, 397 NS, 398 { -1, 1 }, 399 { -2, 1 }, 400 { -1, 1 }, 401 { -2, 1 }, 402 { -1, 1 }, 403 { -2, 1 }, 404 { 0, 1 }, 405 { 0, 1 }, 406 { 0, 1 }, 407 { 0, 1 }, 408 { -1, 1 }, 409 NS, 410 NS, 411 NS, 412 NS, 413 NS, 414 415 { -1, 1 }, 416 NS, 417 { -1, 1 }, 418 NS, 419 NS, 420 NS, 421 NS, 422 423 push1_1i, 424 { 0, 1 }, 425 push1_1i, 426 { -1, 1 }, 427 { -1, 1 }, 428 { 0, 1 }, 429 { 0, 1 }, 430 push2_1i, 431 push1_1i, 432 { -1, 1 }, 433 { 0, 1 }, 434 { -1, 1 }, 435 { 0, 1 }, 436 { 0, 1 }, 437 { 0, 1 }, 438 439 NS, 440 { -1, 1 }, 441 { -1, 1 }, 442 { -3, 1 }, 443 { -3, 1 }, 444 { -1, VMOpcode.IF_INS_LENGTH }, 445 { -1, VMOpcode.IF_INS_LENGTH }, 446 { -1, VMOpcode.IF_INS_LENGTH }, 447 { -1, VMOpcode.IF_INS_LENGTH }, 448 { -1, VMOpcode.IF_INS_LENGTH }, 449 { -1, VMOpcode.IF_INS_LENGTH }, 450 NS, 451 NS, 452 NS, 453 NS, 454 NS, 455 NS, 456 NS, 457 NS, 458 { 0, VMOpcode.GOTO_INS_LENGTH }, 459 NS, 460 NS, 461 NS, 462 NS, 463 464 { -1, 1 }, { -2, 1 }, { -1, 1 }, { -2, 1 }, { -1, 1 }, { 0, 1 }, 471 {VARIABLE_STACK, 3 }, 472 {VARIABLE_STACK, 3 }, 473 {VARIABLE_STACK, 3 }, 474 {VARIABLE_STACK, 3 }, 475 {VARIABLE_STACK, 3 }, 476 {VARIABLE_STACK, 3 }, 477 {VARIABLE_STACK, 3 }, 478 {VARIABLE_STACK, 5 }, 479 480 NS, 481 482 { 1, 3 }, 483 { 0, 2 }, 484 { 0, 3 }, 485 { 0, 1 }, 486 NS, 487 { 0, 3}, 488 { 0, 3 }, 489 NS, 490 NS, 491 NS, 492 NS, 493 { -1, VMOpcode.IF_INS_LENGTH }, 494 { -1, VMOpcode.IF_INS_LENGTH }, 495 {0, VMOpcode.GOTO_W_INS_LENGTH }, 496 NS, 497 NS, 498 499 }; 500 501 506 private void limitHit(IOException ioe) 507 { 508 cb.addLimitExceeded(ioe.toString()); 509 } 510 511 512 516 void addInstr(short opcode) { 517 try { 518 cout.putU1(opcode); 519 } catch (IOException ioe) { 520 limitHit(ioe); 521 } 522 523 if (SanityManager.DEBUG) { 524 if (OPCODE_ACTION[opcode][1] != 1) 525 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" + 526 " writing 1 byte - set as " + OPCODE_ACTION[opcode][1]); 527 } 528 } 529 530 533 void addInstrU2(short opcode, int operand) { 534 535 try { 536 cout.putU1(opcode); 537 cout.putU2(operand); 538 } catch (IOException ioe) { 539 limitHit(ioe); 540 } 541 542 if (SanityManager.DEBUG) { 543 if (OPCODE_ACTION[opcode][1] != 3) 544 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" + 545 " writing 3 bytes - set as " + OPCODE_ACTION[opcode][1]); 546 } 547 } 548 549 552 void addInstrU4(short opcode, int operand) { 553 try { 554 cout.putU1(opcode); 555 cout.putU4(operand); 556 } catch (IOException ioe) { 557 limitHit(ioe); 558 } 559 if (SanityManager.DEBUG) { 560 if (OPCODE_ACTION[opcode][1] != 5) 561 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" + 562 " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]); 563 } 564 } 565 566 567 570 void addInstrU1(short opcode, int operand) { 571 try { 572 cout.putU1(opcode); 573 cout.putU1(operand); 574 } catch (IOException ioe) { 575 limitHit(ioe); 576 } 577 578 if (SanityManager.DEBUG) { 580 581 if (OPCODE_ACTION[opcode][1] != 2) 582 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" + 583 " writing 2 bytes - set as " + OPCODE_ACTION[opcode][1]); 584 585 } 586 } 587 588 596 void addInstrCPE(short opcode, int cpeNum) { 597 if (cpeNum < 256) { 598 addInstrU1(opcode, cpeNum); 599 } 600 else { 601 addInstrU2((short) (opcode+1), cpeNum); 602 } 603 } 604 605 609 void addInstrWide(short opcode, int varNum) { 610 if (varNum < 256) { 611 addInstrU1(opcode, varNum); 612 } 613 else { 614 addInstr(VMOpcode.WIDE); 615 addInstrU2(opcode, varNum); 616 } 617 } 618 619 623 void addInstrU2U1U1(short opcode, int operand1, short operand2, 624 short operand3) { 625 try { 626 cout.putU1(opcode); 627 cout.putU2(operand1); 628 cout.putU1(operand2); 629 cout.putU1(operand3); 630 } catch (IOException ioe) { 631 limitHit(ioe); 632 } 633 if (SanityManager.DEBUG) { 634 if (OPCODE_ACTION[opcode][1] != 5) 635 SanityManager.THROWASSERT("Opcode " + opcode + " incorrect entry in OPCODE_ACTION -" + 636 " writing 5 bytes - set as " + OPCODE_ACTION[opcode][1]); 637 } 638 } 639 640 641 int getPC() { 642 return cout.size() + pcDelta; 643 } 644 645 650 private static int instructionLength(short opcode) 651 { 652 int instructionLength = OPCODE_ACTION[opcode][1]; 653 654 if (SanityManager.DEBUG) 655 { 656 if (instructionLength < 0) 657 SanityManager.THROWASSERT("Opcode without instruction length " + opcode); 658 } 659 660 return instructionLength; 661 } 662 663 671 private final int pcDelta; 672 673 677 final BCClass cb; 678 679 CodeChunk(BCClass cb) { 680 this.cb = cb; 681 cout = new ClassFormatOutput(); 682 try { 683 cout.putU2(0); cout.putU2(0); cout.putU4(0); } catch (IOException ioe) { 687 limitHit(ioe); 688 } 689 pcDelta = - CodeChunk.CODE_OFFSET; 690 } 691 692 699 private CodeChunk(CodeChunk main, int pc, int byteCount) 700 { 701 this.cb = main.cb; 702 ArrayOutputStream aos = 703 new ArrayOutputStream(main.cout.getData()); 704 705 try { 706 aos.setPosition(CODE_OFFSET + pc); 707 aos.setLimit(byteCount); 708 } catch (IOException e) { 709 limitHit(e); 710 } 711 712 cout = new ClassFormatOutput(aos); 713 pcDelta = pc; 714 } 715 716 private final ClassFormatOutput cout; 717 718 727 private void fixLengths(BCMethod mb, int maxStack, int maxLocals, int codeLength) { 728 729 byte[] codeBytes = cout.getData(); 730 731 if (mb != null && maxStack > 65535) 733 cb.addLimitExceeded(mb, "max_stack", 65535, maxStack); 734 735 codeBytes[0] = (byte)(maxStack >> 8 ); 736 codeBytes[1] = (byte)(maxStack ); 737 738 if (mb != null && maxLocals > 65535) 740 cb.addLimitExceeded(mb, "max_locals", 65535, maxLocals); 741 codeBytes[2] = (byte)(maxLocals >> 8 ); 742 codeBytes[3] = (byte)(maxLocals ); 743 744 if (mb != null && codeLength > VMOpcode.MAX_CODE_LENGTH) 746 cb.addLimitExceeded(mb, "code_length", 747 VMOpcode.MAX_CODE_LENGTH, codeLength); 748 codeBytes[4] = (byte)(codeLength >> 24 ); 749 codeBytes[5] = (byte)(codeLength >> 16 ); 750 codeBytes[6] = (byte)(codeLength >> 8 ); 751 codeBytes[7] = (byte)(codeLength ); 752 } 753 754 759 void complete(BCMethod mb, ClassHolder ch, 760 ClassMember method, int maxStack, int maxLocals) { 761 762 int codeLength = getPC(); 763 764 ClassFormatOutput out = cout; 765 766 try { 767 768 out.putU2(0); 770 if (SanityManager.DEBUG) { 771 if (SanityManager.DEBUG_ON("ClassLineNumbers")) { 772 out.putU2(1); 776 int cpiUTF = ch.addUtf8("LineNumberTable"); 777 778 out.putU2(cpiUTF); 779 out.putU4((codeLength * 4) + 2); 780 out.putU2(codeLength); 781 for (int i = 0; i < codeLength; i++) { 782 out.putU2(i); 783 out.putU2(i); 784 } 785 } else { 786 out.putU2(0); } 788 789 } else { 790 out.putU2(0); } 793 } catch (IOException ioe) { 794 limitHit(ioe); 795 } 796 797 fixLengths(mb, maxStack, maxLocals, codeLength); 798 method.addAttribute("Code", out); 799 800 if (SanityManager.DEBUG) 801 { 802 if ((codeLength <= VMOpcode.MAX_CODE_LENGTH) 805 && (mb != null && mb.cb.limitMsg == null)) 806 { 807 int walkedMaxStack = findMaxStack(ch, 0, codeLength); 811 if (walkedMaxStack != maxStack) 812 { 813 SanityManager.THROWASSERT("MAX STACK MISMATCH!! " + 814 maxStack + " <> " + walkedMaxStack); 815 } 816 } 817 } 818 819 } 820 823 short getOpcode(int pc) 824 { 825 return (short) (cout.getData()[CODE_OFFSET + pc] & 0xff); 826 } 827 828 832 private int getU2(int pc) 833 { 834 byte[] codeBytes = cout.getData(); 835 836 int u2p = CODE_OFFSET + pc + 1; 837 838 return ((codeBytes[u2p] & 0xff) << 8) | (codeBytes[u2p+1] & 0xff); 839 } 840 841 845 private int getU4(int pc) 846 { 847 byte[] codeBytes = cout.getData(); 848 849 int u4p = CODE_OFFSET + pc + 1; 850 851 return (((codeBytes[u4p] & 0xff) << 24) | 852 ((codeBytes[u4p+1] & 0xff) << 16) | 853 ((codeBytes[u4p+2] & 0xff) << 8) | 854 ((codeBytes[u4p+3] & 0xff))); 855 } 856 875 CodeChunk insertCodeSpace(int pc, int additionalBytes) 876 { 877 short existingOpcode = getOpcode(pc); 878 879 int lengthOfExistingInstruction 880 = instructionLength(existingOpcode); 881 882 883 if (additionalBytes > 0) 884 { 885 int sizeToMove = (getPC() - pc) - lengthOfExistingInstruction; 887 888 for (int i = 0; i < additionalBytes; i++) 895 addInstr(VMOpcode.NOP); 896 897 byte[] codeBytes = cout.getData(); 899 900 int byteOffset = CODE_OFFSET + pc + lengthOfExistingInstruction; 901 902 903 System.arraycopy( 905 codeBytes, byteOffset, 906 codeBytes, byteOffset + additionalBytes, 907 sizeToMove); 908 909 Arrays.fill(codeBytes, byteOffset, byteOffset + additionalBytes, 915 (byte) VMOpcode.NOP); 916 } 917 918 additionalBytes += lengthOfExistingInstruction; 922 923 929 return new CodeChunk(this, pc, additionalBytes); 930 931 } 932 933 937 938 943 private int findMaxStack(ClassHolder ch, int pc, int codeLength) { 944 945 final int endPc = pc + codeLength; 946 int stack = 0; 947 int maxStack = 0; 948 949 for (; pc < endPc;) { 950 951 short opcode = getOpcode(pc); 952 953 954 int stackDelta = stackWordDelta(ch, pc, opcode); 955 956 stack += stackDelta; 957 if (stack > maxStack) 958 maxStack = stack; 959 960 int[] cond_pcs = findConditionalPCs(pc, opcode); 961 if (cond_pcs != null) { 962 if (cond_pcs[3] != -1) { 964 int blockMaxStack = findMaxStack(ch, cond_pcs[1], 965 cond_pcs[2]); 966 if ((stack + blockMaxStack) > maxStack) 967 maxStack = stack + blockMaxStack; 968 969 pc = cond_pcs[3]; 970 continue; 971 } 972 } 973 974 pc += instructionLength(opcode); 975 } 976 977 return maxStack; 978 } 979 980 984 private int stackWordDelta(ClassHolder ch, int pc, short opcode) { 985 if (SanityManager.DEBUG) { 986 instructionLength(opcode); 988 } 989 990 int stackDelta = OPCODE_ACTION[opcode][0]; 991 if (stackDelta == VARIABLE_STACK) { 992 stackDelta = getVariableStackDelta(ch, pc, opcode); 993 } 994 995 return stackDelta; 996 } 997 998 1002 private String getTypeDescriptor(ClassHolder ch, int pc) { 1003 int cpi = getU2(pc); 1004 1005 1006 CONSTANT_Index_info cii = (CONSTANT_Index_info) ch.getEntry(cpi); 1008 1009 int nameAndType = cii.getI2(); 1011 cii = (CONSTANT_Index_info) ch.getEntry(nameAndType); 1012 1013 int descriptor = cii.getI2(); 1015 CONSTANT_Utf8_info type = (CONSTANT_Utf8_info) ch.getEntry(descriptor); 1016 1017 String vmDescriptor = type.toString(); 1018 1019 return vmDescriptor; 1020 } 1021 1022 1027 private static int getDescriptorWordCount(String vmDescriptor) { 1028 1029 int width; 1030 if (VMDescriptor.DOUBLE.equals(vmDescriptor)) 1031 width = 2; 1032 else if (VMDescriptor.LONG.equals(vmDescriptor)) 1033 width = 2; 1034 else if (vmDescriptor.charAt(0) == VMDescriptor.C_METHOD) { 1035 switch (vmDescriptor.charAt(vmDescriptor.length() - 1)) { 1036 case VMDescriptor.C_DOUBLE: 1037 case VMDescriptor.C_LONG: 1038 width = 2; 1039 break; 1040 case VMDescriptor.C_VOID: 1041 width = 0; 1042 break; 1043 default: 1044 width = 1; 1045 break; 1046 } 1047 } else 1048 width = 1; 1049 1050 return width; 1051 } 1052 1053 1058 private int getVariableStackDelta(ClassHolder ch, int pc, int opcode) { 1059 String vmDescriptor = getTypeDescriptor(ch, pc); 1060 int width = CodeChunk.getDescriptorWordCount(vmDescriptor); 1061 1062 int stackDelta = 0; 1063 switch (opcode) { 1065 case VMOpcode.GETSTATIC: 1066 stackDelta = width; 1067 break; 1068 1069 case VMOpcode.GETFIELD: 1070 stackDelta = width - 1; break; 1072 1073 case VMOpcode.PUTSTATIC: 1074 stackDelta = -width; 1075 break; 1076 1077 case VMOpcode.PUTFIELD: 1078 stackDelta = -width - 1; break; 1080 1081 case VMOpcode.INVOKEVIRTUAL: 1082 case VMOpcode.INVOKESPECIAL: 1083 stackDelta = -1; case VMOpcode.INVOKESTATIC: 1085 stackDelta += (width - CodeChunk.parameterWordCount(vmDescriptor)); 1086 break; 1088 1089 case VMOpcode.INVOKEINTERFACE: 1090 stackDelta = width - getOpcode(pc + 3); 1092 break; 1094 default: 1095 System.out.println("WHO IS THIS "); 1096 break; 1097 1098 } 1099 1100 return stackDelta; 1101 } 1102 1103 1107 private static int parameterWordCount(String methodDescriptor) { 1108 int wordCount = 0; 1109 for (int i = 1;; i++) { 1110 switch (methodDescriptor.charAt(i)) { 1111 case VMDescriptor.C_ENDMETHOD: 1112 return wordCount; 1113 case VMDescriptor.C_DOUBLE: 1114 case VMDescriptor.C_LONG: 1115 wordCount += 2; 1116 break; 1117 case VMDescriptor.C_ARRAY: 1118 do { 1120 i++; 1121 } while (methodDescriptor.charAt(i) == VMDescriptor.C_ARRAY); 1122 if (methodDescriptor.charAt(i) != VMDescriptor.C_CLASS) { 1123 wordCount += 1; 1125 break; 1126 } 1127 1128 1130 case VMDescriptor.C_CLASS: 1131 do { 1133 i++; 1134 } while (methodDescriptor.charAt(i) != VMDescriptor.C_ENDCLASS); 1135 wordCount += 1; 1136 break; 1137 default: 1138 wordCount += 1; 1139 break; 1140 } 1141 } 1142 } 1143 1144 1161 private int[] findConditionalPCs(int pc, short opcode) { 1162 switch (opcode) { 1163 default: 1164 return null; 1165 case VMOpcode.IFNONNULL: 1166 case VMOpcode.IFNULL: 1167 case VMOpcode.IFEQ: 1168 case VMOpcode.IFNE: 1169 break; 1170 } 1171 1172 int then_pc; 1173 int else_pc; 1174 int if_off = getU2(pc); 1175 1176 if ((if_off == 8) 1177 && (getOpcode(pc + VMOpcode.IF_INS_LENGTH) == VMOpcode.GOTO_W)) { 1178 then_pc = pc + VMOpcode.IF_INS_LENGTH + VMOpcode.GOTO_W_INS_LENGTH; 1180 1181 else_pc = pc + VMOpcode.IF_INS_LENGTH 1185 + getU4(pc + VMOpcode.IF_INS_LENGTH); 1186 1187 } else { 1188 then_pc = pc + VMOpcode.IF_INS_LENGTH; 1189 else_pc = pc + if_off; 1190 } 1191 1192 1198 int end_pc = -1; 1199 for (int tpc = then_pc; tpc < else_pc;) { 1200 short opc = getOpcode(tpc); 1201 1202 int[] innerCond = findConditionalPCs(tpc, opc); 1204 if (innerCond != null) { 1205 tpc = innerCond[5]; continue; 1208 } 1209 1210 if (opc == VMOpcode.GOTO) { 1211 if (tpc != (else_pc - VMOpcode.GOTO_INS_LENGTH)) 1217 continue; 1218 1219 end_pc = tpc + getU2(tpc); 1220 break; 1221 } else if (opc == VMOpcode.GOTO_W) { 1222 if (tpc != (else_pc - VMOpcode.GOTO_W_INS_LENGTH)) 1228 continue; 1229 1230 end_pc = tpc + getU4(tpc); 1231 break; 1232 1233 } 1234 tpc += instructionLength(opc); 1235 } 1236 1237 int else_len; 1238 int then_len; 1239 if (end_pc == -1) { 1240 end_pc = else_pc; 1242 else_pc = -1; 1243 1244 then_len = end_pc - then_pc; 1245 else_len = -1; 1246 } else { 1247 then_len = else_pc - then_pc; 1248 else_len = end_pc - else_pc; 1249 } 1250 1251 int[] ret = new int[6]; 1252 1253 ret[0] = pc; 1254 ret[1] = then_pc; 1255 ret[2] = then_len; 1256 ret[3] = else_pc; 1257 ret[4] = else_len; 1258 ret[5] = end_pc; 1259 1260 return ret; 1261 } 1262 1263 1286 final int splitZeroStack(BCMethod mb, ClassHolder ch, final int split_pc, 1287 final int optimalMinLength) { 1288 1289 int splitMinLength = splitMinLength(mb); 1290 1291 int stack = 0; 1292 1293 int possibleSplitLength = -1; 1296 1297 int outerConditionalEnd_pc = -1; 1301 1302 int end_pc = getPC(); for (int pc = split_pc; pc < end_pc;) { 1304 1305 short opcode = getOpcode(pc); 1306 1307 int stackDelta = stackWordDelta(ch, pc, opcode); 1308 1309 stack += stackDelta; 1310 1311 int[] cond_pcs = findConditionalPCs(pc, opcode); 1316 if (cond_pcs != null) { 1317 if (cond_pcs[3] != -1) { 1319 pc = cond_pcs[3]; 1320 continue; 1321 } 1322 1323 if (SanityManager.DEBUG) { 1324 if (outerConditionalEnd_pc != -1) { 1325 if (cond_pcs[5] >= outerConditionalEnd_pc) 1326 SanityManager.THROWASSERT("NESTED CONDITIONALS!"); 1327 } 1328 } 1329 1330 if (outerConditionalEnd_pc == -1) { 1331 outerConditionalEnd_pc = cond_pcs[5]; 1332 } 1333 } 1334 1335 pc += instructionLength(opcode); 1336 1337 if (outerConditionalEnd_pc != -1) { 1339 if (pc > outerConditionalEnd_pc) { 1340 outerConditionalEnd_pc = -1; 1342 } 1343 continue; 1344 } 1345 1346 if (stack != 0) 1347 continue; 1348 1349 int splitLength = pc - split_pc; 1350 1351 if (splitLength < optimalMinLength) { 1352 possibleSplitLength = splitLength; 1354 continue; 1355 } 1356 1357 if (splitLength > BCMethod.CODE_SPLIT_LENGTH - 1) { 1361 splitLength = -1; 1362 } 1363 else if (CodeChunk.isReturn(opcode)) 1364 { 1365 splitLength = -1; 1369 } 1370 1371 if (splitLength == -1) 1374 { 1375 if (possibleSplitLength == -1) 1377 return -1; 1378 1379 if (possibleSplitLength <= splitMinLength) 1382 return -1; 1383 1384 splitLength = possibleSplitLength; 1386 1387 } 1388 1389 1391 BCMethod subMethod = startSubMethod(mb, "void", split_pc, 1392 splitLength); 1393 1394 return splitCodeIntoSubMethod(mb, ch, subMethod, 1395 split_pc, splitLength); 1396 } 1397 return -1; 1398 } 1399 1400 1408 private BCMethod startSubMethod(BCMethod mb, String returnType, 1409 int split_pc, int blockLength) { 1410 1411 boolean needParameters = usesParameters(mb, split_pc, blockLength); 1412 1413 return mb.getNewSubMethod(returnType, needParameters); 1414 } 1415 1416 1423 private boolean usesParameters(BCMethod mb, int pc, int codeLength) { 1424 1425 if (mb.parameters == null) 1427 return false; 1428 1429 boolean isStatic = (mb.myEntry.getModifier() & Modifier.STATIC) != 0; 1430 1431 int endPc = pc + codeLength; 1432 1433 for (; pc < endPc;) { 1434 short opcode = getOpcode(pc); 1435 switch (opcode) { 1436 case VMOpcode.ILOAD_0: 1437 case VMOpcode.LLOAD_0: 1438 case VMOpcode.FLOAD_0: 1439 case VMOpcode.DLOAD_0: 1440 return true; 1441 1442 case VMOpcode.ALOAD_0: 1443 if (isStatic) 1444 return true; 1445 break; 1446 1447 case VMOpcode.ILOAD_1: 1448 case VMOpcode.LLOAD_1: 1449 case VMOpcode.FLOAD_1: 1450 case VMOpcode.DLOAD_1: 1451 case VMOpcode.ALOAD_1: 1452 return true; 1453 1454 case VMOpcode.ILOAD_2: 1455 case VMOpcode.LLOAD_2: 1456 case VMOpcode.FLOAD_2: 1457 case VMOpcode.DLOAD_2: 1458 case VMOpcode.ALOAD_2: 1459 return true; 1460 1461 case VMOpcode.ILOAD_3: 1462 case VMOpcode.LLOAD_3: 1463 case VMOpcode.FLOAD_3: 1464 case VMOpcode.DLOAD_3: 1465 case VMOpcode.ALOAD_3: 1466 return true; 1467 1468 case VMOpcode.ILOAD: 1469 case VMOpcode.LLOAD: 1470 case VMOpcode.FLOAD: 1471 case VMOpcode.DLOAD: 1472 case VMOpcode.ALOAD: 1473 return true; 1474 default: 1475 break; 1476 1477 } 1478 pc += instructionLength(opcode); 1479 } 1480 return false; 1481 } 1482 1495 private int splitCodeIntoSubMethod(BCMethod mb, ClassHolder ch, 1496 BCMethod subMethod, final int split_pc, final int splitLength) { 1497 CodeChunk subChunk = subMethod.myCode; 1498 1499 byte[] codeBytes = cout.getData(); 1500 1501 try { 1505 subChunk.cout.write(codeBytes, CODE_OFFSET + split_pc, splitLength); 1506 } catch (IOException ioe) { 1507 limitHit(ioe); 1508 } 1509 1510 if (subMethod.myReturnType.equals("void")) 1513 subChunk.addInstr(VMOpcode.RETURN); 1514 else 1515 subChunk.addInstr(VMOpcode.ARETURN); 1516 1517 if (cb.limitMsg != null) 1522 return -1; 1523 1524 subMethod.maxStack = subChunk.findMaxStack(ch, 0, subChunk.getPC()); 1525 subMethod.complete(); 1526 1527 return removePushedCode(mb, ch, subMethod, split_pc, splitLength); 1528 } 1529 1530 1547 private int removePushedCode(BCMethod mb, ClassHolder ch, 1548 BCMethod subMethod, final int split_pc, final int splitLength) { 1549 1553 final int codeLength = getPC(); 1555 1556 CodeChunk replaceChunk = new CodeChunk(mb.cb); 1557 mb.myCode = replaceChunk; 1558 mb.maxStack = 0; 1559 1560 byte[] codeBytes = cout.getData(); 1561 1562 if (split_pc != 0) { 1565 try { 1566 replaceChunk.cout.write(codeBytes, CODE_OFFSET, split_pc); 1567 } catch (IOException ioe) { 1568 limitHit(ioe); 1569 } 1570 } 1571 1572 mb.callSubMethod(subMethod); 1574 1575 int postSplit_pc = replaceChunk.getPC(); 1576 1577 1579 int remainingCodePC = split_pc + splitLength; 1580 int remainingCodeLength = codeLength - splitLength - split_pc; 1581 1582 try { 1583 replaceChunk.cout.write(codeBytes, CODE_OFFSET + remainingCodePC, 1584 remainingCodeLength); 1585 } catch (IOException ioe) { 1586 limitHit(ioe); 1587 } 1588 1589 if (cb.limitMsg != null) 1594 return -1; 1595 1596 mb.maxStack = replaceChunk.findMaxStack(ch, 0, replaceChunk.getPC()); 1597 1598 return postSplit_pc; 1599 } 1600 1601 1720 1721 final int splitExpressionOut(final BCMethod mb, final ClassHolder ch, 1722 final int optimalMinLength, 1723 final int maxStack) 1724 { 1725 int bestSplitPC = -1; 1727 int bestSplitBlockLength = -1; 1728 String bestSplitRT = null; 1729 1730 int splitMinLength = splitMinLength(mb); 1731 1732 int[] earliestIndepPC = new int[maxStack+1]; 1759 1760 int stack = 0; 1761 1762 int outerConditionalEnd_pc = -1; 1769 1770 int end_pc = getPC(); 1771 1772 for (int pc = 0; pc < end_pc;) { 1773 1774 short opcode = getOpcode(pc); 1775 1776 int stackDelta = stackWordDelta(ch, pc, opcode); 1777 1778 stack += stackDelta; 1779 1780 int[] cond_pcs = findConditionalPCs(pc, opcode); 1785 if (cond_pcs != null) { 1786 1787 if (true) 1793 return -1; 1794 1795 if (cond_pcs[3] != -1) { 1797 pc = cond_pcs[3]; 1798 continue; 1799 } 1800 1801 if (SanityManager.DEBUG) 1802 { 1803 if (outerConditionalEnd_pc != -1) 1804 { 1805 if (cond_pcs[5] >= outerConditionalEnd_pc) 1806 SanityManager.THROWASSERT("NESTED CONDITIONALS!"); 1807 } 1808 } 1809 1810 if (outerConditionalEnd_pc == -1) 1811 { 1812 outerConditionalEnd_pc = cond_pcs[5]; 1813 } 1814 } 1815 1816 pc += instructionLength(opcode); 1817 1818 if (outerConditionalEnd_pc != -1) { 1820 if (pc > outerConditionalEnd_pc) { 1821 outerConditionalEnd_pc = -1; 1823 } 1824 continue; 1825 } 1826 1827 int opcode_pc = pc - instructionLength(opcode); 1828 switch (opcode) 1829 { 1830 default: 1834 Arrays.fill(earliestIndepPC, 1835 0, stack + 1, -1); 1836 break; 1837 1838 case VMOpcode.ARRAYLENGTH: 1843 case VMOpcode.NOP: 1844 case VMOpcode.CHECKCAST: 1845 case VMOpcode.D2L: 1846 case VMOpcode.DNEG: 1847 case VMOpcode.F2I: 1848 break; 1849 1850 case VMOpcode.ALOAD_0: 1852 case VMOpcode.ALOAD_1: 1853 case VMOpcode.ALOAD_2: 1854 case VMOpcode.ALOAD_3: 1855 case VMOpcode.ALOAD: 1856 case VMOpcode.ACONST_NULL: 1857 case VMOpcode.BIPUSH: 1858 case VMOpcode.FCONST_0: 1859 case VMOpcode.FCONST_1: 1860 case VMOpcode.FCONST_2: 1861 case VMOpcode.FLOAD: 1862 case VMOpcode.ICONST_0: 1863 case VMOpcode.ICONST_1: 1864 case VMOpcode.ICONST_2: 1865 case VMOpcode.ICONST_3: 1866 case VMOpcode.ICONST_4: 1867 case VMOpcode.ICONST_5: 1868 case VMOpcode.ICONST_M1: 1869 case VMOpcode.LDC: 1870 case VMOpcode.LDC_W: 1871 case VMOpcode.SIPUSH: 1872 earliestIndepPC[stack] = opcode_pc; 1873 break; 1874 1875 case VMOpcode.DCONST_0: 1877 case VMOpcode.DCONST_1: 1878 case VMOpcode.LCONST_0: 1879 case VMOpcode.LCONST_1: 1880 case VMOpcode.LDC2_W: 1881 case VMOpcode.LLOAD: 1882 case VMOpcode.LLOAD_0: 1883 case VMOpcode.LLOAD_1: 1884 case VMOpcode.LLOAD_2: 1885 case VMOpcode.LLOAD_3: 1886 earliestIndepPC[stack - 1] = 1887 earliestIndepPC[stack] = opcode_pc; 1888 break; 1889 1890 case VMOpcode.POP: 1893 case VMOpcode.POP2: 1894 break; 1895 1896 case VMOpcode.SWAP: 1897 earliestIndepPC[stack] = earliestIndepPC[stack -1]; 1898 break; 1899 1900 case VMOpcode.I2L: 1902 earliestIndepPC[stack] = earliestIndepPC[stack -1]; 1903 break; 1904 1905 case VMOpcode.GETFIELD: 1906 { 1907 String vmDescriptor = getTypeDescriptor(ch, opcode_pc); 1908 int width = CodeChunk.getDescriptorWordCount(vmDescriptor); 1909 if (width == 2) 1910 earliestIndepPC[stack] = earliestIndepPC[stack -1]; 1911 1912 break; 1913 } 1914 1915 case VMOpcode.INVOKEINTERFACE: 1916 case VMOpcode.INVOKEVIRTUAL: 1917 { 1918 1924 String vmDescriptor = getTypeDescriptor(ch, opcode_pc); 1926 int width = CodeChunk.getDescriptorWordCount(vmDescriptor); 1927 1928 int selfContainedBlockStart; 1931 if (width == 0) 1932 { 1933 selfContainedBlockStart = -1; 1937 } 1939 else if (width == 1) 1940 { 1941 selfContainedBlockStart = earliestIndepPC[stack]; 1944 } 1945 else 1946 { 1947 selfContainedBlockStart = -1; 1952 1953 earliestIndepPC[stack] = 1957 earliestIndepPC[stack - 1]; 1958 } 1959 1960 if (selfContainedBlockStart != -1) 1961 { 1962 int blockLength = pc - selfContainedBlockStart; 1963 1964 if (blockLength <= splitMinLength) 1965 { 1966 } 1968 else if (blockLength > (VMOpcode.MAX_CODE_LENGTH - 1)) 1969 { 1970 } 1973 else 1974 { 1975 int me = vmDescriptor.lastIndexOf(')'); 1978 1979 if (vmDescriptor.charAt(me+1) == 'L') 1980 { 1981 String rt = vmDescriptor.substring(me + 2, 1982 vmDescriptor.length() - 1); 1983 1984 rt = rt.replace('/', '.'); 1986 1987 if (blockLength >= optimalMinLength) 1988 { 1989 BCMethod subMethod = startSubMethod(mb, 1991 rt, selfContainedBlockStart, 1992 blockLength); 1993 1994 return splitCodeIntoSubMethod(mb, ch, subMethod, 1995 selfContainedBlockStart, blockLength); 1996 } 1997 else if (blockLength > bestSplitBlockLength) 1998 { 1999 bestSplitPC = selfContainedBlockStart; 2002 bestSplitBlockLength = blockLength; 2003 bestSplitRT = rt; 2004 } 2005 } 2006 } 2007 } 2008 break; 2009 } 2010 } 2011 2012 } 2013 2014 2015 if (bestSplitBlockLength != -1) { 2016 BCMethod subMethod = startSubMethod(mb, 2017 bestSplitRT, bestSplitPC, 2018 bestSplitBlockLength); 2019 2020 return splitCodeIntoSubMethod(mb, ch, subMethod, 2021 bestSplitPC, bestSplitBlockLength); 2022 } 2023 2024 return -1; 2025 } 2026 2027 2032 private static boolean isReturn(short opcode) 2033 { 2034 switch (opcode) 2035 { 2036 case VMOpcode.RETURN: 2037 case VMOpcode.ARETURN: 2038 case VMOpcode.IRETURN: 2039 case VMOpcode.FRETURN: 2040 case VMOpcode.DRETURN: 2041 case VMOpcode.LRETURN: 2042 return true; 2043 default: 2044 return false; 2045 } 2046 } 2047 2048 2066 private static int splitMinLength(BCMethod mb) { 2067 int min = 1 + 3; 2069 if (mb.parameters != null) { 2070 int paramCount = mb.parameters.length; 2071 2072 min += paramCount; 2073 2074 if (paramCount > 3) 2075 min += (paramCount - 3); 2076 } 2077 2078 return min; 2079 } 2080 2225} 2226 | Popular Tags |