1 16 17 package org.cojen.classfile; 18 19 import org.cojen.classfile.attribute.CodeAttr; 20 import org.cojen.classfile.constant.ConstantClassInfo; 21 import org.cojen.classfile.constant.ConstantFieldInfo; 22 23 29 public class CodeBuilder extends AbstractCodeAssembler implements CodeBuffer, CodeAssembler { 30 private final CodeAttr mCodeAttr; 31 private final ClassFile mClassFile; 32 private final ConstantPool mCp; 33 34 private final InstructionList mInstructions; 35 36 private final LocalVariable mThisReference; 37 private final LocalVariable[] mParameters; 38 39 private final int mTarget; 40 41 private final boolean mSaveLineNumberInfo; 42 private final boolean mSaveLocalVariableInfo; 43 44 48 public CodeBuilder(MethodInfo info) { 49 this(info, true, false); 50 } 51 52 63 public CodeBuilder(MethodInfo info, boolean saveLineNumberInfo, 64 boolean saveLocalVariableInfo) { 65 66 String target = info.getClassFile().getTarget(); 67 if ("1.0".equals(target)) { 68 mTarget = 0x00010000; 69 } else if ("1.1".equals(target)) { 70 mTarget = 0x00010001; 71 } else if ("1.2".equals(target)) { 72 mTarget = 0x00010002; 73 } else if ("1.3".equals(target)) { 74 mTarget = 0x00010003; 75 } else if ("1.4".equals(target)) { 76 mTarget = 0x00010004; 77 } else if ("1.5".equals(target)) { 78 mTarget = 0x00010005; 79 } else if ("1.6".equals(target)) { 80 mTarget = 0x00010006; 81 } else { 82 mTarget = 0x00010000; 83 } 84 85 mCodeAttr = info.getCodeAttr(); 86 mClassFile = info.getClassFile(); 87 mCp = mClassFile.getConstantPool(); 88 mInstructions = new InstructionList(); 89 90 mCodeAttr.setCodeBuffer(this); 91 92 mSaveLineNumberInfo = saveLineNumberInfo; 93 mSaveLocalVariableInfo = saveLocalVariableInfo; 94 95 98 LocalVariable localVar; 99 100 if (info.getModifiers().isStatic()) { 101 mThisReference = null; 102 } else { 103 localVar = mInstructions.createLocalParameter("this", mClassFile.getType()); 104 mThisReference = localVar; 105 106 if (saveLocalVariableInfo) { 107 mCodeAttr.localVariableUse(localVar); 108 } 109 } 110 111 TypeDesc[] paramTypes = info.getMethodDescriptor().getParameterTypes(); 112 int paramSize = paramTypes.length; 113 114 mParameters = new LocalVariable[paramSize]; 115 116 for (int i = 0; i<paramTypes.length; i++) { 117 localVar = mInstructions.createLocalParameter(null, paramTypes[i]); 118 mParameters[i] = localVar; 119 if (saveLocalVariableInfo) { 120 mCodeAttr.localVariableUse(localVar); 121 } 122 } 123 } 124 125 public int getMaxStackDepth() { 126 return mInstructions.getMaxStackDepth(); 127 } 128 129 public int getMaxLocals() { 130 return mInstructions.getMaxLocals(); 131 } 132 133 public byte[] getByteCodes() { 134 return mInstructions.getByteCodes(); 135 } 136 137 public ExceptionHandler[] getExceptionHandlers() { 138 return mInstructions.getExceptionHandlers(); 139 } 140 141 private void addCode(int stackAdjust, byte opcode) { 142 mInstructions.new CodeInstruction(stackAdjust, new byte[] {opcode}); 143 } 144 145 private void addCode(int stackAdjust, byte opcode, byte operand) { 146 mInstructions.new CodeInstruction 147 (stackAdjust, new byte[] {opcode, operand}); 148 } 149 150 private void addCode(int stackAdjust, byte opcode, short operand) { 151 mInstructions.new CodeInstruction 152 (stackAdjust, 153 new byte[] {opcode, (byte)(operand >> 8), (byte)operand}); 154 } 155 156 private void addCode(int stackAdjust, byte opcode, int operand) { 157 byte[] bytes = new byte[5]; 158 159 bytes[0] = opcode; 160 bytes[1] = (byte)(operand >> 24); 161 bytes[2] = (byte)(operand >> 16); 162 bytes[3] = (byte)(operand >> 8); 163 bytes[4] = (byte)operand; 164 165 mInstructions.new CodeInstruction(stackAdjust, bytes); 166 } 167 168 private void addCode(int stackAdjust, byte opcode, ConstantInfo info) { 169 mInstructions.new ConstantOperandInstruction 172 (stackAdjust, 173 new byte[] {opcode, (byte)0, (byte)0}, info); 174 } 175 176 private String getClassName(TypeDesc classDesc) throws IllegalArgumentException { 177 if (classDesc.isPrimitive()) { 178 throw new IllegalArgumentException ("Primitive type not allowed"); 179 } 180 if (classDesc.isArray()) { 181 throw new IllegalArgumentException ("Array type not allowed"); 182 } 183 return classDesc.getRootName(); 184 } 185 186 public int getParameterCount() { 187 return mParameters.length; 188 } 189 190 public LocalVariable getParameter(int index) { 191 return mParameters[index]; 192 } 193 194 public LocalVariable createLocalVariable(String name, TypeDesc type) { 195 LocalVariable localVar = mInstructions.createLocalVariable(name, type); 196 197 if (mSaveLocalVariableInfo) { 198 mCodeAttr.localVariableUse(localVar); 199 } 200 201 return localVar; 202 } 203 204 public Label createLabel() { 205 return mInstructions.new LabelInstruction(); 206 } 207 208 public void exceptionHandler(Location startLocation, 209 Location endLocation, 210 String catchClassName) { 211 Location catchLocation = createLabel().setLocation(); 212 213 ConstantClassInfo catchClass; 214 if (catchClassName == null) { 215 catchClass = null; 216 } else { 217 catchClass = mCp.addConstantClass(catchClassName); 218 } 219 220 ExceptionHandler handler = 221 new ExceptionHandler(startLocation, endLocation, 222 catchLocation, catchClass); 223 224 mInstructions.addExceptionHandler(handler); 225 } 226 227 public void mapLineNumber(int lineNumber) { 228 if (mSaveLineNumberInfo) { 229 mCodeAttr.mapLineNumber(createLabel().setLocation(), lineNumber); 230 } 231 } 232 233 235 public void loadNull() { 236 addCode(1, Opcode.ACONST_NULL); 237 } 238 239 public void loadConstant(String value) { 240 if (value == null) { 241 loadNull(); 242 return; 243 } 244 245 int strlen = value.length(); 246 247 if (strlen <= (65535 / 3)) { 248 ConstantInfo info = mCp.addConstantString(value); 250 mInstructions.new LoadConstantInstruction(1, info); 251 return; 252 } 253 254 256 int utflen = 0; 257 258 for (int i=0; i<strlen; i++) { 259 int c = value.charAt(i); 260 if ((c >= 0x0001) && (c <= 0x007F)) { 261 utflen++; 262 } else if (c > 0x07FF) { 263 utflen += 3; 264 } else { 265 utflen += 2; 266 } 267 } 268 269 if (utflen <= 65535) { 270 ConstantInfo info = mCp.addConstantString(value); 271 mInstructions.new LoadConstantInstruction(1, info); 272 return; 273 } 274 275 277 TypeDesc stringBufferDesc; 278 if (mTarget >= 0x00010005) { 279 stringBufferDesc = TypeDesc.forClass("java.lang.StringBuilder"); 280 } else { 281 stringBufferDesc = TypeDesc.forClass(StringBuffer .class); 282 } 283 284 TypeDesc intDesc = TypeDesc.INT; 285 TypeDesc stringDesc = TypeDesc.STRING; 286 TypeDesc[] stringParam = new TypeDesc[] {stringDesc}; 287 288 newObject(stringBufferDesc); 289 dup(); 290 loadConstant(strlen); 291 invokeConstructor(stringBufferDesc, new TypeDesc[] {intDesc}); 292 293 int beginIndex; 294 int endIndex = 0; 295 296 while (endIndex < strlen) { 297 beginIndex = endIndex; 298 299 utflen = 0; 301 for (; endIndex < strlen; endIndex++) { 302 int c = value.charAt(endIndex); 303 int size; 304 if ((c >= 0x0001) && (c <= 0x007F)) { 305 size = 1; 306 } else if (c > 0x07FF) { 307 size = 3; 308 } else { 309 size = 2; 310 } 311 312 if ((utflen + size) > 65535) { 313 break; 314 } else { 315 utflen += size; 316 } 317 } 318 319 String substr = value.substring(beginIndex, endIndex); 320 321 ConstantInfo info = mCp.addConstantString(substr); 322 mInstructions.new LoadConstantInstruction(1, info); 323 324 invokeVirtual(stringBufferDesc, "append", 325 stringBufferDesc, stringParam); 326 } 327 328 invokeVirtual(stringBufferDesc, "toString", stringDesc, null); 329 } 330 331 public void loadConstant(TypeDesc type) throws IllegalStateException { 332 if (type == null) { 333 loadNull(); 334 return; 335 } 336 337 if (type.isPrimitive()) { 338 if (mTarget < 0x00010001) { 339 throw new IllegalStateException 340 ("Loading constant primitive classes not supported below target version 1.1"); 341 } 342 loadStaticField(type.toObjectType(), "TYPE", TypeDesc.forClass(Class .class)); 343 } else { 344 if (mTarget < 0x00010005) { 345 throw new IllegalStateException 346 ("Loading constant object classes not supported below target version 1.5"); 347 } 348 ConstantInfo info = mCp.addConstantClass(type); 349 mInstructions.new LoadConstantInstruction(1, info); 350 } 351 } 352 353 public void loadConstant(boolean value) { 354 loadConstant(value ? 1 : 0); 355 } 356 357 public void loadConstant(int value) { 358 if (-1 <= value && value <= 5) { 359 byte op; 360 361 switch(value) { 362 case -1: 363 op = Opcode.ICONST_M1; 364 break; 365 case 0: 366 op = Opcode.ICONST_0; 367 break; 368 case 1: 369 op = Opcode.ICONST_1; 370 break; 371 case 2: 372 op = Opcode.ICONST_2; 373 break; 374 case 3: 375 op = Opcode.ICONST_3; 376 break; 377 case 4: 378 op = Opcode.ICONST_4; 379 break; 380 case 5: 381 op = Opcode.ICONST_5; 382 break; 383 default: 384 op = Opcode.NOP; 385 } 386 387 addCode(1, op); 388 } else if (-128 <= value && value <= 127) { 389 addCode(1, Opcode.BIPUSH, (byte)value); 390 } else if (-32768 <= value && value <= 32767) { 391 addCode(1, Opcode.SIPUSH, (short)value); 392 } else { 393 ConstantInfo info = mCp.addConstantInteger(value); 394 mInstructions.new LoadConstantInstruction(1, info); 395 } 396 } 397 398 public void loadConstant(long value) { 399 if (value == 0) { 400 addCode(2, Opcode.LCONST_0); 401 } else if (value == 1) { 402 addCode(2, Opcode.LCONST_1); 403 } else { 404 ConstantInfo info = mCp.addConstantLong(value); 405 mInstructions.new LoadConstantInstruction(2, info, true); 406 } 407 } 408 409 public void loadConstant(float value) { 410 if (value == 0) { 411 addCode(1, Opcode.FCONST_0); 412 } else if (value == 1) { 413 addCode(1, Opcode.FCONST_1); 414 } else if (value == 2) { 415 addCode(1, Opcode.FCONST_2); 416 } else { 417 ConstantInfo info = mCp.addConstantFloat(value); 418 mInstructions.new LoadConstantInstruction(1, info); 419 } 420 } 421 422 public void loadConstant(double value) { 423 if (value == 0) { 424 addCode(2, Opcode.DCONST_0); 425 } else if (value == 1) { 426 addCode(2, Opcode.DCONST_1); 427 } else { 428 ConstantInfo info = mCp.addConstantDouble(value); 429 mInstructions.new LoadConstantInstruction(2, info, true); 430 } 431 } 432 433 435 public void loadLocal(LocalVariable local) { 436 if (local == null) { 437 throw new IllegalArgumentException ("No local variable specified"); 438 } 439 int stackAdjust = local.getType().isDoubleWord() ? 2 : 1; 440 mInstructions.new LoadLocalInstruction(stackAdjust, local); 441 } 442 443 public void loadThis() { 444 if (mThisReference != null) { 445 loadLocal(mThisReference); 446 } else { 447 throw new IllegalStateException 448 ("Attempt to load \"this\" reference in a static method"); 449 } 450 } 451 452 454 public void storeLocal(LocalVariable local) { 455 if (local == null) { 456 throw new IllegalArgumentException ("No local variable specified"); 457 } 458 int stackAdjust = local.getType().isDoubleWord() ? -2 : -1; 459 mInstructions.new StoreLocalInstruction(stackAdjust, local); 460 } 461 462 464 public void loadFromArray(TypeDesc type) { 465 byte op; 466 int stackAdjust = -1; 467 468 switch (type.getTypeCode()) { 469 case TypeDesc.INT_CODE: 470 op = Opcode.IALOAD; 471 break; 472 case TypeDesc.BOOLEAN_CODE: 473 case TypeDesc.BYTE_CODE: 474 op = Opcode.BALOAD; 475 break; 476 case TypeDesc.SHORT_CODE: 477 op = Opcode.SALOAD; 478 break; 479 case TypeDesc.CHAR_CODE: 480 op = Opcode.CALOAD; 481 break; 482 case TypeDesc.FLOAT_CODE: 483 op = Opcode.FALOAD; 484 break; 485 case TypeDesc.LONG_CODE: 486 stackAdjust = 0; 487 op = Opcode.LALOAD; 488 break; 489 case TypeDesc.DOUBLE_CODE: 490 stackAdjust = 0; 491 op = Opcode.DALOAD; 492 break; 493 default: 494 op = Opcode.AALOAD; 495 break; 496 } 497 498 addCode(stackAdjust, op); 499 } 500 501 503 public void storeToArray(TypeDesc type) { 504 byte op; 505 int stackAdjust = -3; 506 507 switch (type.getTypeCode()) { 508 case TypeDesc.INT_CODE: 509 op = Opcode.IASTORE; 510 break; 511 case TypeDesc.BOOLEAN_CODE: 512 case TypeDesc.BYTE_CODE: 513 op = Opcode.BASTORE; 514 break; 515 case TypeDesc.SHORT_CODE: 516 op = Opcode.SASTORE; 517 break; 518 case TypeDesc.CHAR_CODE: 519 op = Opcode.CASTORE; 520 break; 521 case TypeDesc.FLOAT_CODE: 522 op = Opcode.FASTORE; 523 break; 524 case TypeDesc.LONG_CODE: 525 stackAdjust = -4; 526 op = Opcode.LASTORE; 527 break; 528 case TypeDesc.DOUBLE_CODE: 529 stackAdjust = -4; 530 op = Opcode.DASTORE; 531 break; 532 default: 533 op = Opcode.AASTORE; 534 break; 535 } 536 537 addCode(stackAdjust, op); 538 } 539 540 542 public void loadField(String fieldName, 543 TypeDesc type) { 544 getfield(0, Opcode.GETFIELD, constantField(fieldName, type), type); 545 } 546 547 public void loadField(String className, 548 String fieldName, 549 TypeDesc type) { 550 551 getfield(0, Opcode.GETFIELD, 552 mCp.addConstantField(className, fieldName, type), 553 type); 554 } 555 556 public void loadField(TypeDesc classDesc, 557 String fieldName, 558 TypeDesc type) { 559 560 loadField(getClassName(classDesc), fieldName, type); 561 } 562 563 public void loadStaticField(String fieldName, 564 TypeDesc type) { 565 566 getfield(1, Opcode.GETSTATIC, constantField(fieldName, type), type); 567 } 568 569 public void loadStaticField(String className, 570 String fieldName, 571 TypeDesc type) { 572 573 getfield(1, Opcode.GETSTATIC, 574 mCp.addConstantField(className, fieldName, type), 575 type); 576 } 577 578 public void loadStaticField(TypeDesc classDesc, 579 String fieldName, 580 TypeDesc type) { 581 582 loadStaticField(getClassName(classDesc), fieldName, type); 583 } 584 585 private void getfield(int stackAdjust, byte opcode, ConstantInfo info, 586 TypeDesc type) { 587 if (type.isDoubleWord()) { 588 stackAdjust++; 589 } 590 addCode(stackAdjust, opcode, info); 591 } 592 593 private ConstantFieldInfo constantField(String fieldName, 594 TypeDesc type) { 595 return mCp.addConstantField 596 (mClassFile.getClassName(), fieldName, type); 597 } 598 599 601 public void storeField(String fieldName, 602 TypeDesc type) { 603 604 putfield(-1, Opcode.PUTFIELD, constantField(fieldName, type), type); 605 } 606 607 public void storeField(String className, 608 String fieldName, 609 TypeDesc type) { 610 611 putfield(-1, Opcode.PUTFIELD, 612 mCp.addConstantField(className, fieldName, type), 613 type); 614 } 615 616 public void storeField(TypeDesc classDesc, 617 String fieldName, 618 TypeDesc type) { 619 620 storeField(getClassName(classDesc), fieldName, type); 621 } 622 623 public void storeStaticField(String fieldName, 624 TypeDesc type) { 625 626 putfield(0, Opcode.PUTSTATIC, constantField(fieldName, type), type); 627 } 628 629 public void storeStaticField(String className, 630 String fieldName, 631 TypeDesc type) { 632 633 putfield(0, Opcode.PUTSTATIC, 634 mCp.addConstantField(className, fieldName, type), 635 type); 636 } 637 638 public void storeStaticField(TypeDesc classDesc, 639 String fieldName, 640 TypeDesc type) { 641 642 storeStaticField(getClassName(classDesc), fieldName, type); 643 } 644 645 private void putfield(int stackAdjust, byte opcode, ConstantInfo info, 646 TypeDesc type) { 647 if (type.isDoubleWord()) { 648 stackAdjust -= 2; 649 } else { 650 stackAdjust--; 651 } 652 addCode(stackAdjust, opcode, info); 653 } 654 655 657 public void returnVoid() { 658 addCode(0, Opcode.RETURN); 659 } 660 661 public void returnValue(TypeDesc type) { 662 int stackAdjust = -1; 663 byte op; 664 665 switch (type.getTypeCode()) { 666 case TypeDesc.INT_CODE: 667 case TypeDesc.BOOLEAN_CODE: 668 case TypeDesc.BYTE_CODE: 669 case TypeDesc.SHORT_CODE: 670 case TypeDesc.CHAR_CODE: 671 op = Opcode.IRETURN; 672 break; 673 case TypeDesc.FLOAT_CODE: 674 op = Opcode.FRETURN; 675 break; 676 case TypeDesc.LONG_CODE: 677 stackAdjust = -2; 678 op = Opcode.LRETURN; 679 break; 680 case TypeDesc.DOUBLE_CODE: 681 stackAdjust = -2; 682 op = Opcode.DRETURN; 683 break; 684 case TypeDesc.VOID_CODE: 685 stackAdjust = 0; 686 op = Opcode.RETURN; 687 break; 688 default: 689 op = Opcode.ARETURN; 690 break; 691 } 692 693 addCode(stackAdjust, op); 694 } 695 696 698 public void convert(TypeDesc fromType, TypeDesc toType) { 699 convert(fromType, toType, CONVERT_FP_NORMAL); 700 } 701 702 public void convert(TypeDesc fromType, TypeDesc toType, int fpConvertMode) { 703 if (fpConvertMode < 0 || fpConvertMode > CONVERT_FP_RAW_BITS) { 704 throw new IllegalArgumentException ("Illegal floating point conversion mode"); 705 } 706 707 if (toType == TypeDesc.OBJECT) { 708 if (fromType.isPrimitive()) { 709 toType = fromType.toObjectType(); 710 } else { 711 return; 712 } 713 } 714 715 if (fromType == toType) { 716 return; 717 } 718 719 TypeDesc fromPrimitiveType = fromType.toPrimitiveType(); 720 if (fromPrimitiveType == null) { 721 if (!toType.isPrimitive()) { 722 Class fromClass = fromType.toClass(); 723 if (fromClass != null) { 724 Class toClass = toType.toClass(); 725 if (toClass != null && toClass.isAssignableFrom(fromClass)) { 726 return; 727 } 728 } 729 } 730 throw invalidConversion(fromType, toType); 731 } 732 int fromTypeCode = fromPrimitiveType.getTypeCode(); 733 734 if (toType.toClass() == Number .class) { 735 switch (fromTypeCode) { 736 case TypeDesc.INT_CODE: 737 case TypeDesc.BYTE_CODE: 738 case TypeDesc.SHORT_CODE: 739 case TypeDesc.LONG_CODE: 740 case TypeDesc.FLOAT_CODE: 741 case TypeDesc.DOUBLE_CODE: 742 if (fromType.isPrimitive()) { 743 toType = fromType.toObjectType(); 744 } else { 745 return; 746 } 747 } 748 } 749 750 TypeDesc toPrimitiveType = toType.toPrimitiveType(); 751 if (toPrimitiveType == null) { 752 throw invalidConversion(fromType, toType); 753 } 754 int toTypeCode = toPrimitiveType.getTypeCode(); 755 756 Label end = createLabel(); 758 759 doConversion: { 760 int stackAdjust = 0; 761 byte op; 762 763 switch (fromTypeCode) { 764 case TypeDesc.INT_CODE: 765 case TypeDesc.BYTE_CODE: 766 case TypeDesc.SHORT_CODE: 767 case TypeDesc.CHAR_CODE: 768 case TypeDesc.BOOLEAN_CODE: 769 switch (toTypeCode) { 770 case TypeDesc.BYTE_CODE: 771 op = (fromTypeCode == TypeDesc.BYTE_CODE) ? 772 Opcode.NOP : Opcode.I2B; 773 break; 774 case TypeDesc.SHORT_CODE: 775 op = (fromTypeCode == TypeDesc.SHORT_CODE) ? 776 Opcode.NOP : Opcode.I2S; 777 break; 778 case TypeDesc.CHAR_CODE: 779 op = (fromTypeCode == TypeDesc.CHAR_CODE) ? 780 Opcode.NOP : Opcode.I2C; 781 break; 782 case TypeDesc.FLOAT_CODE: 783 op = Opcode.I2F; 784 break; 785 case TypeDesc.LONG_CODE: 786 stackAdjust = 1; 787 op = Opcode.I2L; 788 break; 789 case TypeDesc.DOUBLE_CODE: 790 stackAdjust = 1; 791 op = Opcode.I2D; 792 break; 793 case TypeDesc.INT_CODE: 794 op = Opcode.NOP; 795 break; 796 case TypeDesc.BOOLEAN_CODE: 797 if (!fromType.isPrimitive()) { 798 if (!toType.isPrimitive()) { 799 nullConvert(end); 800 } 801 unbox(fromType, fromPrimitiveType); 802 } 803 toBoolean(!toType.isPrimitive()); 804 break doConversion; 805 default: 806 throw invalidConversion(fromType, toType); 807 } 808 break; 809 810 case TypeDesc.LONG_CODE: 811 switch (toTypeCode) { 812 case TypeDesc.INT_CODE: 813 stackAdjust = -1; 814 op = Opcode.L2I; 815 break; 816 case TypeDesc.FLOAT_CODE: 817 stackAdjust = -1; 818 op = Opcode.L2F; 819 break; 820 case TypeDesc.DOUBLE_CODE: 821 op = Opcode.L2D; 822 break; 823 case TypeDesc.BYTE_CODE: 824 case TypeDesc.CHAR_CODE: 825 case TypeDesc.SHORT_CODE: 826 addCode(-1, Opcode.L2I); 827 convert(TypeDesc.INT, toPrimitiveType); 828 case TypeDesc.LONG_CODE: 830 op = Opcode.NOP; 831 break; 832 case TypeDesc.BOOLEAN_CODE: 833 if (!fromType.isPrimitive()) { 834 if (!toType.isPrimitive()) { 835 nullConvert(end); 836 } 837 unbox(fromType, fromPrimitiveType); 838 } 839 loadConstant(0L); 840 math(Opcode.LCMP); 841 toBoolean(!toType.isPrimitive()); 842 break doConversion; 843 default: 844 throw invalidConversion(fromType, toType); 845 } 846 break; 847 848 case TypeDesc.FLOAT_CODE: 849 switch (toTypeCode) { 850 case TypeDesc.INT_CODE: 851 op = Opcode.F2I; 852 break; 853 case TypeDesc.LONG_CODE: 854 stackAdjust = 1; 855 op = Opcode.F2L; 856 break; 857 case TypeDesc.DOUBLE_CODE: 858 stackAdjust = 1; 859 op = Opcode.F2D; 860 break; 861 case TypeDesc.BYTE_CODE: 862 case TypeDesc.CHAR_CODE: 863 case TypeDesc.SHORT_CODE: 864 addCode(0, Opcode.F2I); 865 convert(TypeDesc.INT, toPrimitiveType); 866 case TypeDesc.FLOAT_CODE: 868 op = Opcode.NOP; 869 break; 870 case TypeDesc.BOOLEAN_CODE: 871 if (!fromType.isPrimitive()) { 872 if (!toType.isPrimitive()) { 873 nullConvert(end); 874 } 875 unbox(fromType, fromPrimitiveType); 876 } 877 loadConstant(0.0f); 878 math(Opcode.FCMPG); 879 toBoolean(!toType.isPrimitive()); 880 break doConversion; 881 default: 882 throw invalidConversion(fromType, toType); 883 } 884 break; 885 886 case TypeDesc.DOUBLE_CODE: 887 switch (toTypeCode) { 888 case TypeDesc.INT_CODE: 889 stackAdjust = -1; 890 op = Opcode.D2I; 891 break; 892 case TypeDesc.FLOAT_CODE: 893 stackAdjust = -1; 894 op = Opcode.D2F; 895 break; 896 case TypeDesc.LONG_CODE: 897 op = Opcode.D2L; 898 break; 899 case TypeDesc.BYTE_CODE: 900 case TypeDesc.CHAR_CODE: 901 case TypeDesc.SHORT_CODE: 902 addCode(-1, Opcode.D2I); 903 convert(TypeDesc.INT, toPrimitiveType); 904 case TypeDesc.DOUBLE_CODE: 906 op = Opcode.NOP; 907 break; 908 case TypeDesc.BOOLEAN_CODE: 909 if (!fromType.isPrimitive()) { 910 if (!toType.isPrimitive()) { 911 nullConvert(end); 912 } 913 unbox(fromType, fromPrimitiveType); 914 } 915 loadConstant(0.0d); 916 math(Opcode.DCMPG); 917 toBoolean(!toType.isPrimitive()); 918 break doConversion; 919 default: 920 throw invalidConversion(fromType, toType); 921 } 922 break; 923 924 default: 925 throw invalidConversion(fromType, toType); 926 } 927 928 if (!fromType.isPrimitive()) { 929 if (!toType.isPrimitive()) { 930 nullConvert(end); 931 } 932 unbox(fromType, fromPrimitiveType); 933 } 934 935 if (toType.isPrimitive()) { 936 if (op != Opcode.NOP) { 937 convertPrimitive(stackAdjust, op, fpConvertMode); 938 } 939 } else { 940 if (op == Opcode.NOP) { 941 prebox(toPrimitiveType, toType); 942 } else if (!fromPrimitiveType.isDoubleWord() && 943 toPrimitiveType.isDoubleWord()) { 944 prebox(fromPrimitiveType, toType); 947 convertPrimitive(stackAdjust, op, fpConvertMode); 948 } else { 949 convertPrimitive(stackAdjust, op, fpConvertMode); 950 prebox(toPrimitiveType, toType); 951 } 952 box(toPrimitiveType, toType); 953 } 954 } 955 956 end.setLocation(); 957 } 958 959 963 private void unbox(TypeDesc from, TypeDesc to) { 964 String methodName; 965 966 switch (to.getTypeCode()) { 967 case TypeDesc.BOOLEAN_CODE: 968 methodName = "booleanValue"; 969 break; 970 case TypeDesc.CHAR_CODE: 971 methodName = "charValue"; 972 break; 973 case TypeDesc.FLOAT_CODE: 974 methodName = "floatValue"; 975 break; 976 case TypeDesc.DOUBLE_CODE: 977 methodName = "doubleValue"; 978 break; 979 case TypeDesc.BYTE_CODE: 980 methodName = "byteValue"; 981 break; 982 case TypeDesc.SHORT_CODE: 983 methodName = "shortValue"; 984 break; 985 case TypeDesc.INT_CODE: 986 methodName = "intValue"; 987 break; 988 case TypeDesc.LONG_CODE: 989 methodName = "longValue"; 990 break; 991 default: 992 return; 993 } 994 995 invokeVirtual(from.getRootName(), methodName, to, null); 996 } 997 998 1002 private void prebox(TypeDesc from, TypeDesc to) { 1003 if (mTarget >= 0x00010005) { 1004 return; 1007 } 1008 1009 1013 switch (from.getTypeCode()) { 1014 default: 1015 break; 1016 case TypeDesc.BOOLEAN_CODE: 1017 if (to.toPrimitiveType().getTypeCode() == TypeDesc.BOOLEAN_CODE) { 1018 break; 1019 } 1020 case TypeDesc.CHAR_CODE: 1022 case TypeDesc.FLOAT_CODE: 1023 case TypeDesc.BYTE_CODE: 1024 case TypeDesc.SHORT_CODE: 1025 case TypeDesc.INT_CODE: 1026 newObject(to); 1027 dupX1(); 1028 swap(); 1029 break; 1030 case TypeDesc.DOUBLE_CODE: 1031 case TypeDesc.LONG_CODE: 1032 newObject(to); 1033 dupX2(); 1034 dupX2(); 1035 pop(); 1036 break; 1037 } 1038 } 1039 1040 1044 private void box(TypeDesc from, TypeDesc to) { 1045 if (mTarget >= 0x00010005) { 1046 invokeStatic(to.getRootName(), "valueOf", to, new TypeDesc[] {from}); 1048 return; 1049 } 1050 1051 switch (from.getTypeCode()) { 1052 case TypeDesc.BOOLEAN_CODE: 1053 toBoolean(true); 1054 break; 1055 case TypeDesc.CHAR_CODE: 1056 case TypeDesc.FLOAT_CODE: 1057 case TypeDesc.BYTE_CODE: 1058 case TypeDesc.SHORT_CODE: 1059 case TypeDesc.INT_CODE: 1060 case TypeDesc.DOUBLE_CODE: 1061 case TypeDesc.LONG_CODE: 1062 invokeConstructor(to.getRootName(), new TypeDesc[]{from}); 1063 break; 1064 } 1065 } 1066 1067 private void toBoolean(boolean box) { 1069 if (box && mTarget >= 0x00010004) { 1070 invokeStatic("java.lang.Boolean", "valueOf", 1072 TypeDesc.BOOLEAN.toObjectType(), 1073 new TypeDesc[] {TypeDesc.BOOLEAN}); 1074 return; 1075 } 1076 1077 Label nonZero = createLabel(); 1078 Label done = createLabel(); 1079 ifZeroComparisonBranch(nonZero, "!="); 1080 if (box) { 1081 TypeDesc newType = TypeDesc.BOOLEAN.toObjectType(); 1082 loadStaticField(newType.getRootName(), "FALSE", newType); 1083 branch(done); 1084 nonZero.setLocation(); 1085 loadStaticField(newType.getRootName(), "TRUE", newType); 1086 } else { 1087 loadConstant(false); 1088 branch(done); 1089 nonZero.setLocation(); 1090 loadConstant(true); 1091 } 1092 done.setLocation(); 1093 } 1094 1095 private void convertPrimitive(int stackAdjust, byte op, int fpConvertMode) { 1096 if (fpConvertMode != CONVERT_FP_NORMAL) { 1097 switch (op) { 1098 case Opcode.I2F: 1099 invokeStatic("java.lang.Float", "intBitsToFloat", TypeDesc.FLOAT, 1100 new TypeDesc[] {TypeDesc.INT}); 1101 return; 1102 1103 case Opcode.L2D: 1104 invokeStatic("java.lang.Double", "longBitsToDouble", TypeDesc.DOUBLE, 1105 new TypeDesc[] {TypeDesc.LONG}); 1106 return; 1107 1108 case Opcode.F2I: 1109 if (fpConvertMode == CONVERT_FP_RAW_BITS) { 1110 invokeStatic("java.lang.Float", "floatToRawIntBits", TypeDesc.INT, 1111 new TypeDesc[] {TypeDesc.FLOAT}); 1112 } else { 1113 invokeStatic("java.lang.Float", "floatToIntBits", TypeDesc.INT, 1114 new TypeDesc[] {TypeDesc.FLOAT}); 1115 } 1116 return; 1117 1118 case Opcode.D2L: 1119 if (fpConvertMode == CONVERT_FP_RAW_BITS) { 1120 invokeStatic("java.lang.Double", "doubleToRawLongBits", TypeDesc.LONG, 1121 new TypeDesc[] {TypeDesc.DOUBLE}); 1122 } else { 1123 invokeStatic("java.lang.Double", "doubleToLongBits", TypeDesc.LONG, 1124 new TypeDesc[] {TypeDesc.DOUBLE}); 1125 } 1126 return; 1127 } 1128 } 1129 1130 addCode(stackAdjust, op); 1131 } 1132 1133 private void nullConvert(Label end) { 1136 LocalVariable temp = createLocalVariable("temp", TypeDesc.OBJECT); 1137 storeLocal(temp); 1138 loadLocal(temp); 1139 Label notNull = createLabel(); 1140 ifNullBranch(notNull, false); 1141 loadNull(); 1142 branch(end); 1143 notNull.setLocation(); 1144 loadLocal(temp); 1145 } 1146 1147 private IllegalArgumentException invalidConversion 1148 (TypeDesc from, TypeDesc to) 1149 { 1150 throw new IllegalArgumentException 1151 ("Invalid conversion: " + from.getFullName() + " to " + 1152 to.getFullName()); 1153 } 1154 1155 1157 public void invokeVirtual(String methodName, 1158 TypeDesc ret, 1159 TypeDesc[] params) { 1160 1161 ConstantInfo info = mCp.addConstantMethod 1162 (mClassFile.getClassName(), methodName, ret, params); 1163 1164 int stackAdjust = returnSize(ret) - 1; 1165 if (params != null) { 1166 stackAdjust -= argSize(params); 1167 } 1168 1169 addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info); 1170 } 1171 1172 public void invokeVirtual(String className, 1173 String methodName, 1174 TypeDesc ret, 1175 TypeDesc[] params) { 1176 ConstantInfo info = 1177 mCp.addConstantMethod(className, methodName, ret, params); 1178 1179 int stackAdjust = returnSize(ret) - 1; 1180 if (params != null) { 1181 stackAdjust -= argSize(params); 1182 } 1183 1184 addCode(stackAdjust, Opcode.INVOKEVIRTUAL, info); 1185 } 1186 1187 public void invokeVirtual(TypeDesc classDesc, 1188 String methodName, 1189 TypeDesc ret, 1190 TypeDesc[] params) { 1191 1192 invokeVirtual(getClassName(classDesc), methodName, ret, params); 1193 } 1194 1195 public void invokeStatic(String methodName, 1196 TypeDesc ret, 1197 TypeDesc[] params) { 1198 ConstantInfo info = mCp.addConstantMethod 1199 (mClassFile.getClassName(), methodName, ret, params); 1200 1201 int stackAdjust = returnSize(ret) - 0; 1202 if (params != null) { 1203 stackAdjust -= argSize(params); 1204 } 1205 1206 addCode(stackAdjust, Opcode.INVOKESTATIC, info); 1207 } 1208 1209 public void invokeStatic(String className, 1210 String methodName, 1211 TypeDesc ret, 1212 TypeDesc[] params) { 1213 ConstantInfo info = 1214 mCp.addConstantMethod(className, methodName, ret, params); 1215 1216 int stackAdjust = returnSize(ret) - 0; 1217 if (params != null) { 1218 stackAdjust -= argSize(params); 1219 } 1220 1221 addCode(stackAdjust, Opcode.INVOKESTATIC, info); 1222 } 1223 1224 public void invokeStatic(TypeDesc classDesc, 1225 String methodName, 1226 TypeDesc ret, 1227 TypeDesc[] params) { 1228 1229 invokeStatic(getClassName(classDesc), methodName, ret, params); 1230 } 1231 1232 public void invokeInterface(String className, 1233 String methodName, 1234 TypeDesc ret, 1235 TypeDesc[] params) { 1236 1237 ConstantInfo info = 1238 mCp.addConstantInterfaceMethod(className, methodName, ret, params); 1239 1240 int paramCount = 1; 1241 if (params != null) { 1242 paramCount += argSize(params); 1243 } 1244 1245 int stackAdjust = returnSize(ret) - paramCount; 1246 1247 byte[] bytes = new byte[5]; 1248 1249 bytes[0] = Opcode.INVOKEINTERFACE; 1250 bytes[3] = (byte)paramCount; 1253 1255 mInstructions.new ConstantOperandInstruction(stackAdjust, bytes, info); 1256 } 1257 1258 public void invokeInterface(TypeDesc classDesc, 1259 String methodName, 1260 TypeDesc ret, 1261 TypeDesc[] params) { 1262 1263 invokeInterface(getClassName(classDesc), methodName, ret, params); 1264 } 1265 1266 public void invokePrivate(String methodName, 1267 TypeDesc ret, 1268 TypeDesc[] params) { 1269 ConstantInfo info = mCp.addConstantMethod 1270 (mClassFile.getClassName(), methodName, ret, params); 1271 1272 int stackAdjust = returnSize(ret) - 1; 1273 if (params != null) { 1274 stackAdjust -= argSize(params); 1275 } 1276 1277 addCode(stackAdjust, Opcode.INVOKESPECIAL, info); 1278 } 1279 1280 public void invokeSuper(String superClassName, 1281 String methodName, 1282 TypeDesc ret, 1283 TypeDesc[] params) { 1284 ConstantInfo info = 1285 mCp.addConstantMethod(superClassName, methodName, ret, params); 1286 1287 int stackAdjust = returnSize(ret) - 1; 1288 if (params != null) { 1289 stackAdjust -= argSize(params); 1290 } 1291 1292 addCode(stackAdjust, Opcode.INVOKESPECIAL, info); 1293 } 1294 1295 public void invokeSuper(TypeDesc superClassDesc, 1296 String methodName, 1297 TypeDesc ret, 1298 TypeDesc[] params) { 1299 1300 invokeSuper(getClassName(superClassDesc), methodName, ret, params); 1301 } 1302 1303 public void invokeConstructor(TypeDesc[] params) { 1304 ConstantInfo info = 1305 mCp.addConstantConstructor(mClassFile.getClassName(), params); 1306 1307 int stackAdjust = -1; 1308 if (params != null) { 1309 stackAdjust -= argSize(params); 1310 } 1311 1312 addCode(stackAdjust, Opcode.INVOKESPECIAL, info); 1313 } 1314 1315 public void invokeConstructor(String className, TypeDesc[] params) { 1316 ConstantInfo info = mCp.addConstantConstructor(className, params); 1317 1318 int stackAdjust = -1; 1319 if (params != null) { 1320 stackAdjust -= argSize(params); 1321 } 1322 1323 addCode(stackAdjust, Opcode.INVOKESPECIAL, info); 1324 } 1325 1326 public void invokeConstructor(TypeDesc classDesc, TypeDesc[] params) { 1327 invokeConstructor(getClassName(classDesc), params); 1328 } 1329 1330 public void invokeSuperConstructor(TypeDesc[] params) { 1331 invokeConstructor(mClassFile.getSuperClassName(), params); 1332 } 1333 1334 private int returnSize(TypeDesc ret) { 1335 if (ret == null || ret == TypeDesc.VOID) { 1336 return 0; 1337 } 1338 if (ret.isDoubleWord()) { 1339 return 2; 1340 } 1341 return 1; 1342 } 1343 1344 private int argSize(TypeDesc[] params) { 1345 int size = 0; 1346 if (params != null) { 1347 for (int i=0; i<params.length; i++) { 1348 size += returnSize(params[i]); 1349 } 1350 } 1351 return size; 1352 } 1353 1354 1356 public void newObject(TypeDesc type) { 1357 if (type.isArray()) { 1358 newObject(type, 1); 1359 } else { 1360 ConstantInfo info = mCp.addConstantClass(type); 1361 addCode(1, Opcode.NEW, info); 1362 } 1363 } 1364 1365 public void newObject(TypeDesc type, int dimensions) { 1366 if (dimensions <= 0) { 1367 ConstantInfo info = mCp.addConstantClass(type); 1369 addCode(1, Opcode.NEW, info); 1370 return; 1371 } 1372 1373 TypeDesc componentType = type.getComponentType(); 1374 1375 if (dimensions == 1) { 1376 if (componentType.isPrimitive()) { 1377 addCode(0, Opcode.NEWARRAY, (byte)componentType.getTypeCode()); 1378 return; 1379 } 1380 addCode(0, Opcode.ANEWARRAY, mCp.addConstantClass(componentType)); 1381 return; 1382 } 1383 1384 int stackAdjust = -(dimensions - 1); 1385 ConstantInfo info = mCp.addConstantClass(type); 1386 byte[] bytes = new byte[4]; 1387 1388 bytes[0] = Opcode.MULTIANEWARRAY; 1389 bytes[3] = (byte)dimensions; 1392 1393 mInstructions.new ConstantOperandInstruction(stackAdjust, bytes, info); 1394 } 1395 1396 1398 public void dup() { 1399 addCode(1, Opcode.DUP); 1400 } 1401 1402 public void dupX1() { 1403 addCode(1, Opcode.DUP_X1); 1404 } 1405 1406 public void dupX2() { 1407 addCode(1, Opcode.DUP_X2); 1408 } 1409 1410 public void dup2() { 1411 addCode(2, Opcode.DUP2); 1412 } 1413 1414 public void dup2X1() { 1415 addCode(2, Opcode.DUP2_X1); 1416 } 1417 1418 public void dup2X2() { 1419 addCode(2, Opcode.DUP2_X2); 1420 } 1421 1422 public void pop() { 1423 addCode(-1, Opcode.POP); 1424 } 1425 1426 public void pop2() { 1427 addCode(-2, Opcode.POP2); 1428 } 1429 1430 public void swap() { 1431 addCode(0, Opcode.SWAP); 1432 } 1433 1434 public void swap2() { 1435 dup2X2(); 1436 pop2(); 1437 } 1438 1439 1441 private void branch(int stackAdjust, Location location, byte opcode) { 1442 mInstructions.new BranchInstruction(stackAdjust, opcode, location); 1443 } 1444 1445 public void branch(Location location) { 1446 branch(0, location, Opcode.GOTO); 1447 } 1448 1449 public void ifNullBranch(Location location, boolean choice) { 1450 branch(-1, location, choice ? Opcode.IFNULL : Opcode.IFNONNULL); 1451 } 1452 1453 public void ifEqualBranch(Location location, boolean choice) { 1454 branch(-2, location, choice ? Opcode.IF_ACMPEQ : Opcode.IF_ACMPNE); 1455 } 1456 1457 public void ifZeroComparisonBranch(Location location, String choice) 1458 throws IllegalArgumentException { 1459 1460 choice = choice.intern(); 1461 1462 byte opcode; 1463 if (choice == "==") { 1464 opcode = Opcode.IFEQ; 1465 } else if (choice == "!=") { 1466 opcode = Opcode.IFNE; 1467 } else if (choice == "<") { 1468 opcode = Opcode.IFLT; 1469 } else if (choice == ">=") { 1470 opcode = Opcode.IFGE; 1471 } else if (choice == ">") { 1472 opcode = Opcode.IFGT; 1473 } else if (choice == "<=") { 1474 opcode = Opcode.IFLE; 1475 } else { 1476 throw new IllegalArgumentException 1477 ("Invalid comparision choice: " + choice); 1478 } 1479 1480 branch(-1, location, opcode); 1481 } 1482 1483 public void ifComparisonBranch(Location location, String choice) 1484 throws IllegalArgumentException { 1485 1486 choice = choice.intern(); 1487 1488 byte opcode; 1489 if (choice == "==") { 1490 opcode = Opcode.IF_ICMPEQ; 1491 } else if (choice == "!=") { 1492 opcode = Opcode.IF_ICMPNE; 1493 } else if (choice == "<") { 1494 opcode = Opcode.IF_ICMPLT; 1495 } else if (choice == ">=") { 1496 opcode = Opcode.IF_ICMPGE; 1497 } else if (choice == ">") { 1498 opcode = Opcode.IF_ICMPGT; 1499 } else if (choice == "<=") { 1500 opcode = Opcode.IF_ICMPLE; 1501 } else { 1502 throw new IllegalArgumentException 1503 ("Invalid comparision choice: " + choice); 1504 } 1505 1506 branch(-2, location, opcode); 1507 } 1508 1509 public void switchBranch(int[] cases, 1510 Location[] locations, Location defaultLocation) { 1511 1512 mInstructions.new SwitchInstruction(cases, locations, defaultLocation); 1513 } 1514 1515 public void jsr(Location location) { 1516 branch(1, location, Opcode.JSR); 1518 } 1519 1520 public void ret(LocalVariable local) { 1521 if (local == null) { 1522 throw new IllegalArgumentException ("No local variable specified"); 1523 } 1524 1525 mInstructions.new RetInstruction(local); 1526 } 1527 1528 1530 public void math(byte opcode) { 1531 int stackAdjust; 1532 1533 switch(opcode) { 1534 case Opcode.INEG: 1535 case Opcode.LNEG: 1536 case Opcode.FNEG: 1537 case Opcode.DNEG: 1538 stackAdjust = 0; 1539 break; 1540 case Opcode.IADD: 1541 case Opcode.ISUB: 1542 case Opcode.IMUL: 1543 case Opcode.IDIV: 1544 case Opcode.IREM: 1545 case Opcode.IAND: 1546 case Opcode.IOR: 1547 case Opcode.IXOR: 1548 case Opcode.ISHL: 1549 case Opcode.ISHR: 1550 case Opcode.IUSHR: 1551 case Opcode.FADD: 1552 case Opcode.FSUB: 1553 case Opcode.FMUL: 1554 case Opcode.FDIV: 1555 case Opcode.FREM: 1556 case Opcode.FCMPG: 1557 case Opcode.FCMPL: 1558 case Opcode.LSHL: 1559 case Opcode.LSHR: 1560 case Opcode.LUSHR: 1561 stackAdjust = -1; 1562 break; 1563 case Opcode.LADD: 1564 case Opcode.LSUB: 1565 case Opcode.LMUL: 1566 case Opcode.LDIV: 1567 case Opcode.LREM: 1568 case Opcode.LAND: 1569 case Opcode.LOR: 1570 case Opcode.LXOR: 1571 case Opcode.DADD: 1572 case Opcode.DSUB: 1573 case Opcode.DMUL: 1574 case Opcode.DDIV: 1575 case Opcode.DREM: 1576 stackAdjust = -2; 1577 break; 1578 case Opcode.LCMP: 1579 case Opcode.DCMPG: 1580 case Opcode.DCMPL: 1581 stackAdjust = -3; 1582 break; 1583 default: 1584 throw new IllegalArgumentException 1585 ("Not a math opcode: " + Opcode.getMnemonic(opcode)); 1586 } 1587 1588 addCode(stackAdjust, opcode); 1589 } 1590 1591 1593 public void arrayLength() { 1594 addCode(0, Opcode.ARRAYLENGTH); 1595 } 1596 1597 public void throwObject() { 1598 addCode(-1, Opcode.ATHROW); 1599 } 1600 1601 public void checkCast(TypeDesc type) { 1602 ConstantInfo info = mCp.addConstantClass(type); 1603 addCode(0, Opcode.CHECKCAST, info); 1604 } 1605 1606 public void instanceOf(TypeDesc type) { 1607 ConstantInfo info = mCp.addConstantClass(type); 1608 addCode(0, Opcode.INSTANCEOF, info); 1609 } 1610 1611 public void integerIncrement(LocalVariable local, int amount) { 1612 if (local == null) { 1613 throw new IllegalArgumentException ("No local variable specified"); 1614 } 1615 1616 if (-32768 <= amount && amount <= 32767) { 1617 mInstructions.new ShortIncrementInstruction(local, (short)amount); 1618 } else { 1619 1622 loadLocal(local); 1623 loadConstant(amount); 1624 math(Opcode.IADD); 1625 storeLocal(local); 1626 } 1627 } 1628 1629 public void monitorEnter() { 1630 addCode(-1, Opcode.MONITORENTER); 1631 } 1632 1633 public void monitorExit() { 1634 addCode(-1, Opcode.MONITOREXIT); 1635 } 1636 1637 public void nop() { 1638 addCode(0, Opcode.NOP); 1639 } 1640 1641 public void breakpoint() { 1642 addCode(0, Opcode.BREAKPOINT); 1643 } 1644} 1645 | Popular Tags |