1 21 22 package org.apache.derby.impl.services.bytecode; 23 24 import org.apache.derby.iapi.services.compiler.ClassBuilder; 25 import org.apache.derby.iapi.services.compiler.MethodBuilder; 26 import org.apache.derby.iapi.services.classfile.ClassFormatOutput; 27 import org.apache.derby.iapi.services.compiler.LocalField; 28 import org.apache.derby.iapi.services.classfile.ClassHolder; 29 import org.apache.derby.iapi.services.classfile.ClassMember; 30 31 import org.apache.derby.iapi.services.sanity.SanityManager; 32 33 import org.apache.derby.iapi.services.classfile.VMDescriptor; 34 import org.apache.derby.iapi.services.classfile.VMOpcode; 35 36 import java.lang.reflect.Modifier ; 37 import java.util.Vector ; 38 import java.io.IOException ; 39 40 67 class BCMethod implements MethodBuilder { 68 69 76 static final int CODE_SPLIT_LENGTH = VMOpcode.MAX_CODE_LENGTH; 77 78 final BCClass cb; 79 protected final ClassHolder modClass; final String myReturnType; 81 82 86 private final String myName; 87 88 92 BCLocalField[] parameters; 93 94 98 private final String [] parameterTypes; 99 100 101 Vector thrownExceptions; 103 CodeChunk myCode; 104 protected ClassMember myEntry; 105 106 private int currentVarNum; 107 private int statementNum; 108 109 114 private boolean handlingOverflow; 115 116 119 private int subMethodCount; 120 121 BCMethod(ClassBuilder cb, 122 String returnType, 123 String methodName, 124 int modifiers, 125 String [] parms, 126 BCJava factory) { 127 128 this.cb = (BCClass) cb; 129 modClass = this.cb.modify(); 130 myReturnType = returnType; 131 myName = methodName; 132 133 if (SanityManager.DEBUG) { 134 this.cb.validateType(returnType); 135 } 136 137 if ((modifiers & Modifier.STATIC) == 0 ) 139 currentVarNum = 1; 140 141 String [] vmParamterTypes; 142 143 if (parms != null && parms.length != 0) { 144 int len = parms.length; 145 vmParamterTypes = new String [len]; 146 parameters = new BCLocalField[len]; 147 for (int i = 0; i < len; i++) { 148 Type t = factory.type(parms[i]); 149 parameters[i] = new BCLocalField(t, currentVarNum); 150 currentVarNum += t.width(); 151 152 vmParamterTypes[i] = t.vmName(); 154 } 155 } 156 else 157 vmParamterTypes = BCMethodDescriptor.EMPTY; 158 159 String sig = BCMethodDescriptor.get(vmParamterTypes, factory.type(returnType).vmName(), factory); 161 162 myEntry = modClass.addMember(methodName, sig, modifiers); 164 165 myCode = new CodeChunk(this.cb); 167 168 parameterTypes = parms; 169 } 170 174 179 public String getName() { 180 return myName; 181 } 182 183 public void getParameter(int id) { 184 185 int num = parameters[id].cpi; 186 short typ = parameters[id].type.vmType(); 187 if (num < 4) 188 myCode.addInstr((short) (CodeChunk.LOAD_VARIABLE_FAST[typ]+num)); 189 else 190 myCode.addInstrWide(CodeChunk.LOAD_VARIABLE[typ], num); 191 192 growStack(parameters[id].type); 193 } 194 195 199 public void addThrownException(String exceptionClass) { 200 201 if (SanityManager.DEBUG) 206 { 207 if (myCode.getPC() != 0) 208 SanityManager.THROWASSERT("Adding exception after code generation " + exceptionClass 209 + " to method " + getName()); 210 } 211 212 if (thrownExceptions == null) 213 thrownExceptions = new Vector (); 214 thrownExceptions.addElement(exceptionClass); 215 } 216 217 226 public void complete() { 227 228 233 if (myCode.getPC() > CODE_SPLIT_LENGTH) 234 splitMethod(); 235 236 writeExceptions(); 238 239 myCode.complete(this, modClass, myEntry, maxStack, currentVarNum); 242 } 243 244 260 private void splitMethod() { 261 262 int split_pc = 0; 263 boolean splittingZeroStack = true; 264 for (int codeLength = myCode.getPC(); 265 (cb.limitMsg == null) && 266 (codeLength > CODE_SPLIT_LENGTH); 267 codeLength = myCode.getPC()) 268 { 269 int lengthToCheck = codeLength - split_pc; 270 271 int optimalMinLength; 272 if (codeLength < CODE_SPLIT_LENGTH * 2) { 273 optimalMinLength = codeLength - CODE_SPLIT_LENGTH; 275 } else { 276 optimalMinLength = CODE_SPLIT_LENGTH - 1; 279 } 280 281 if (optimalMinLength > lengthToCheck) 282 optimalMinLength = lengthToCheck; 283 284 if (splittingZeroStack) 285 { 286 split_pc = myCode.splitZeroStack(this, modClass, split_pc, 287 optimalMinLength); 288 } 289 else 290 { 291 split_pc = myCode.splitExpressionOut(this, modClass, 296 optimalMinLength, maxStack); 297 298 } 299 300 if (split_pc < 0) { 304 if (!splittingZeroStack) 305 break; 306 splittingZeroStack = false; 307 split_pc = 0; 308 } 309 310 } 313 314 315 } 316 317 320 321 327 ClassHolder constantPool() { 328 return modClass; 329 } 330 331 332 336 337 345 protected void writeExceptions() { 346 if (thrownExceptions == null) 347 return; 348 349 int numExc = thrownExceptions.size(); 350 351 if (numExc != 0) { 353 354 try{ 355 ClassFormatOutput eout = new ClassFormatOutput((numExc * 2) + 2); 356 357 eout.putU2(numExc); 359 for (int i = 0; i < numExc; i++) { 360 String e = thrownExceptions.elementAt(i).toString(); 362 int ei2 = modClass.addClassReference(e); 363 364 eout.putU2(ei2); 366 } 367 368 myEntry.addAttribute("Exceptions", eout); 369 370 } catch (IOException ioe) { 371 } 372 } 373 } 374 375 378 379 385 private Type[] stackTypes = new Type[8]; 386 387 392 private int stackTypeOffset; 393 394 399 int maxStack; 400 401 404 private int stackDepth; 405 406 private void growStack(int size, Type type) { 407 stackDepth += size; 408 if (stackDepth > maxStack) 409 maxStack = stackDepth; 410 411 if (stackTypeOffset >= stackTypes.length) { 412 413 Type[] newStackTypes = new Type[stackTypes.length + 8]; 414 System.arraycopy(stackTypes, 0, newStackTypes, 0, stackTypes.length); 415 stackTypes = newStackTypes; 416 } 417 418 stackTypes[stackTypeOffset++] = type; 419 420 if (SanityManager.DEBUG) { 421 422 int sum = 0; 423 for (int i = 0 ; i < stackTypeOffset; i++) { 424 sum += stackTypes[i].width(); 425 } 426 if (sum != stackDepth) { 427 SanityManager.THROWASSERT("invalid stack depth " + stackDepth + " calc " + sum); 428 } 429 } 430 } 431 432 private void growStack(Type type) { 433 growStack(type.width(), type); 434 } 435 436 private Type popStack() { 437 stackTypeOffset--; 438 Type topType = stackTypes[stackTypeOffset]; 439 stackDepth -= topType.width(); 440 return topType; 441 442 } 443 444 private Type[] copyStack() 445 { 446 Type[] stack = new Type[stackTypeOffset]; 447 System.arraycopy(stackTypes, 0, stack, 0, stackTypeOffset); 448 return stack; 449 } 450 451 public void pushThis() { 452 myCode.addInstr(VMOpcode.ALOAD_0); 453 growStack(1, cb.classType); 454 } 455 456 public void push(byte value) { 457 push(value, Type.BYTE); 458 } 459 460 public void push(boolean value) { 461 push(value ? 1 : 0, Type.BOOLEAN); 462 } 463 464 public void push(short value) { 465 push(value, Type.SHORT); 466 } 467 468 public void push(int value) { 469 push(value, Type.INT); 470 } 471 472 public void dup() { 473 Type dup = popStack(); 474 myCode.addInstr(dup.width() == 2 ? VMOpcode.DUP2 : VMOpcode.DUP); 475 growStack(dup); 476 growStack(dup); 477 478 } 479 480 public void swap() { 481 482 485 Type wB = popStack(); 486 Type wA = popStack(); 487 growStack(wB); 488 growStack(wA); 489 490 if (wB.width() == 1) { 491 if (wA.width() == 1) { 493 myCode.addInstr(VMOpcode.SWAP); 494 return; 495 } else { 496 myCode.addInstr(VMOpcode.DUP_X2); 497 myCode.addInstr(VMOpcode.POP); 498 } 499 } else { 500 if (wA.width() == 1) { 502 myCode.addInstr(VMOpcode.DUP2_X1); 503 myCode.addInstr(VMOpcode.POP2); 504 } else { 505 myCode.addInstr(VMOpcode.DUP2_X2); 506 myCode.addInstr(VMOpcode.POP2); 507 } 508 } 509 510 growStack(wB); 513 popStack(); 514 515 } 516 517 526 private void push(int value, Type type) { 527 528 CodeChunk chunk = myCode; 529 530 if (value >= -1 && value <= 5) 531 chunk.addInstr((short)(VMOpcode.ICONST_0+value)); 532 else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) 533 chunk.addInstrU1(VMOpcode.BIPUSH,value); 534 else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) 535 chunk.addInstrU2(VMOpcode.SIPUSH,value); 536 else { 537 int cpe = modClass.addConstant(value); 538 addInstrCPE(VMOpcode.LDC, cpe); 539 } 540 growStack(type.width(), type); 541 542 } 543 544 557 public void push(long value) { 558 CodeChunk chunk = myCode; 559 560 if (value == 0L || value == 1L) { 561 short opcode = value == 0L ? VMOpcode.LCONST_0 : VMOpcode.LCONST_1; 562 chunk.addInstr(opcode); 563 } else if (value >= Integer.MIN_VALUE && value <= Integer.MAX_VALUE) { 564 push((int) value, Type.LONG); 566 chunk.addInstr(VMOpcode.I2L); 567 return; 568 } else { 569 int cpe = modClass.addConstant(value); 570 chunk.addInstrU2(VMOpcode.LDC2_W, cpe); 571 } 572 growStack(2, Type.LONG); 573 } 574 public void push(float value) { 575 576 CodeChunk chunk = myCode; 577 578 if (value == 0.0) 579 { 580 chunk.addInstr(VMOpcode.FCONST_0); 581 } 582 else if (value == 1.0) 583 { 584 chunk.addInstr(VMOpcode.FCONST_1); 585 } 586 else if (value == 2.0) 587 { 588 chunk.addInstr(VMOpcode.FCONST_2); 589 } 590 else 591 { 592 int cpe = modClass.addConstant(value); 593 addInstrCPE(VMOpcode.LDC, cpe); 594 } 595 growStack(1, Type.FLOAT); 596 } 597 598 public void push(double value) { 599 CodeChunk chunk = myCode; 600 601 if (value == 0.0) { 602 chunk.addInstr(VMOpcode.DCONST_0); 603 } 604 else { 605 int cpe = modClass.addConstant(value); 606 chunk.addInstrU2(VMOpcode.LDC2_W, cpe); 607 } 608 growStack(2, Type.DOUBLE); 609 } 610 public void push(String value) { 611 int cpe = modClass.addConstant(value); 612 addInstrCPE(VMOpcode.LDC, cpe); 613 growStack(1, Type.STRING); 614 } 615 616 617 public void methodReturn() { 618 619 short opcode; 620 if (stackDepth != 0) { 621 Type topType = popStack(); 622 opcode = CodeChunk.RETURN_OPCODE[topType.vmType()]; 623 } else { 624 opcode = VMOpcode.RETURN; 625 } 626 627 myCode.addInstr(opcode); 628 629 if (SanityManager.DEBUG) { 630 if (stackDepth != 0) 631 SanityManager.THROWASSERT("items left on stack " + stackDepth); 632 } 633 } 634 635 public Object describeMethod(short opcode, String declaringClass, String methodName, String returnType) { 636 637 Type rt = cb.factory.type(returnType); 638 639 String methodDescriptor = BCMethodDescriptor.get(BCMethodDescriptor.EMPTY, rt.vmName(), cb.factory); 640 641 if ((declaringClass == null) && (opcode != VMOpcode.INVOKESTATIC)) { 642 643 Type dt = stackTypes[stackTypeOffset - 1]; 644 645 if (declaringClass == null) 646 declaringClass = dt.javaName(); 647 } 648 649 int cpi = modClass.addMethodReference(declaringClass, methodName, 650 methodDescriptor, opcode == VMOpcode.INVOKEINTERFACE); 651 652 return new BCMethodCaller(opcode, rt, cpi); 653 } 654 655 public int callMethod(Object methodDescriptor) { 656 657 popStack(); 659 660 BCMethodCaller mc = (BCMethodCaller) methodDescriptor; 661 662 int cpi = mc.cpi; 663 short opcode = mc.opcode; 664 665 if (opcode == VMOpcode.INVOKEINTERFACE) { 666 myCode.addInstrU2U1U1(opcode, cpi, (short) 1, (short) 0); 667 } 668 else 669 myCode.addInstrU2(opcode, cpi); 670 671 Type rt = mc.type; 673 int rw = rt.width(); 674 if (rw != 0) 675 growStack(rw, rt); 676 else 677 { 678 if (stackDepth == 0) 679 overflowMethodCheck(); 680 } 681 return cpi; 682 } 683 684 public int callMethod(short opcode, String declaringClass, String methodName, 685 String returnType, int numArgs) { 686 687 Type rt = cb.factory.type(returnType); 688 689 int initialStackDepth = stackDepth; 690 691 693 String [] debugParameterTypes = null; 694 String [] vmParameterTypes; 695 if (numArgs == 0) { 696 vmParameterTypes = BCMethodDescriptor.EMPTY; 697 } else { 698 if (SanityManager.DEBUG) { 699 debugParameterTypes = new String [numArgs]; 700 } 701 vmParameterTypes = new String [numArgs]; 702 for (int i = numArgs - 1; i >= 0; i--) { 703 Type at = popStack(); 704 705 vmParameterTypes[i] = at.vmName(); 706 if (SanityManager.DEBUG) { 707 debugParameterTypes[i] = at.javaName(); 708 } 709 } 710 } 711 712 String methodDescriptor = BCMethodDescriptor.get(vmParameterTypes, rt.vmName(), cb.factory); 713 714 Type dt = null; 715 if (opcode != VMOpcode.INVOKESTATIC) { 716 717 dt = popStack(); 718 } 719 Type dtu = vmNameDeclaringClass(declaringClass); 720 if (dtu != null) 721 dt = dtu; 722 723 int cpi = modClass.addMethodReference(dt.vmNameSimple, methodName, 724 methodDescriptor, opcode == VMOpcode.INVOKEINTERFACE); 725 726 if (opcode == VMOpcode.INVOKEINTERFACE) { 727 short callArgCount = (short) (initialStackDepth - stackDepth); 728 myCode.addInstrU2U1U1(opcode, cpi, callArgCount, (short) 0); 729 } 730 else 731 myCode.addInstrU2(opcode, cpi); 732 733 int rw = rt.width(); 735 if (rw != 0) 736 growStack(rw, rt); 737 else 738 { 739 if (stackDepth == 0) 740 overflowMethodCheck(); 741 } 742 if (SanityManager.DEBUG) { 744 745 d_BCValidate.checkMethod(opcode, dt, methodName, debugParameterTypes, rt); 746 } 747 748 return cpi; 749 } 750 751 private Type vmNameDeclaringClass(String declaringClass) { 752 if (declaringClass == null) 753 return null; 754 return cb.factory.type(declaringClass); 755 } 756 757 public void callSuper() { 758 759 pushThis(); 760 callMethod(VMOpcode.INVOKESPECIAL, cb.getSuperClassName(), "<init>", "void", 0); 761 } 762 763 public void pushNewStart(String className) { 764 765 int cpi = modClass.addClassReference(className); 766 767 myCode.addInstrU2(VMOpcode.NEW, cpi); 769 myCode.addInstr(VMOpcode.DUP); 770 771 Type nt = cb.factory.type(className); 774 growStack(1, nt); 775 growStack(1, nt); 776 } 777 778 public void pushNewComplete(int numArgs) { 779 callMethod(VMOpcode.INVOKESPECIAL, (String ) null, "<init>", "void", numArgs); 780 } 781 782 public void upCast(String className) { 783 Type uct = cb.factory.type(className); 784 785 stackTypes[stackTypeOffset - 1] = uct; 786 } 789 790 public void cast(String className) { 791 792 Type tbc = stackTypes[stackTypeOffset - 1]; 802 803 short sourceType = tbc.vmType(); 804 805 if (sourceType == BCExpr.vm_reference) 806 { 807 if (className.equals(tbc.javaName())) 809 { 810 return; 812 } 813 } 814 815 Type ct = cb.factory.type(className); 816 popStack(); 817 818 short targetType = ct.vmType(); 819 820 if (SanityManager.DEBUG) { 821 822 if (!((sourceType == BCExpr.vm_reference && 823 targetType == BCExpr.vm_reference) || 824 (sourceType != BCExpr.vm_reference && 825 targetType != BCExpr.vm_reference))) { 826 SanityManager.THROWASSERT("Both or neither must be object types " + ct.javaName() + " " + tbc.javaName()); 827 } 828 } 829 830 if (sourceType == BCExpr.vm_reference) { 832 833 int cpi = modClass.addClassReference(ct.vmNameSimple); 834 myCode.addInstrU2(VMOpcode.CHECKCAST, cpi); 835 } 836 else { 838 short opcode = VMOpcode.NOP; 839 840 while (sourceType!=targetType && opcode!=VMOpcode.BAD) { 848 short[] currentConversion = 849 CodeChunk.CAST_CONVERSION_INFO[sourceType][targetType]; 850 sourceType = currentConversion[1]; 851 opcode = currentConversion[0]; 852 if (opcode != VMOpcode.NOP) { 853 myCode.addInstr(opcode); 854 } 855 } 856 if (SanityManager.DEBUG) { 857 SanityManager.ASSERT(opcode != VMOpcode.BAD, 858 "BAD VMOpcode not expected in cast"); 859 } 860 } 861 growStack(ct); 862 } 863 864 public void isInstanceOf(String className) { 865 int cpi = modClass.addClassReference(className); 866 myCode.addInstrU2(VMOpcode.INSTANCEOF, cpi); 867 popStack(); 868 growStack(1, Type.BOOLEAN); 869 } 870 871 public void pushNull(String type) { 872 myCode.addInstr(VMOpcode.ACONST_NULL); 873 growStack(1, cb.factory.type(type)); 874 } 875 876 877 public void getField(LocalField field) { 878 879 BCLocalField lf = (BCLocalField) field; 880 Type lt = lf.type; 881 882 pushThis(); 883 myCode.addInstrU2(VMOpcode.GETFIELD, lf.cpi); 884 885 popStack(); 886 growStack(lt); 887 888 } 889 890 public void getField(String declaringClass, String fieldName, String fieldType) { 891 Type dt = popStack(); 892 893 Type dtu = vmNameDeclaringClass(declaringClass); 894 if (dtu != null) 895 dt = dtu; 896 897 getField(VMOpcode.GETFIELD, dt.vmNameSimple, fieldName, fieldType); 898 } 899 902 public void getStaticField(String declaringClass, String fieldName, String fieldType) { 903 getField(VMOpcode.GETSTATIC, declaringClass, fieldName, fieldType); 904 } 905 906 private void getField(short opcode, String declaringClass, String fieldName, String fieldType) { 907 908 Type ft = cb.factory.type(fieldType); 909 int cpi = modClass.addFieldReference(vmNameDeclaringClass(declaringClass).vmNameSimple, fieldName, ft.vmName()); 910 myCode.addInstrU2(opcode, cpi); 911 912 growStack(ft); 913 } 914 915 919 public void setField(LocalField field) { 920 BCLocalField lf = (BCLocalField) field; 921 Type lt = lf.type; 922 923 putField(lf.type, lf.cpi, false); 924 925 if (stackDepth == 0) 926 overflowMethodCheck(); 927 } 928 929 948 public void putField(LocalField field) { 949 BCLocalField lf = (BCLocalField) field; 950 Type lt = lf.type; 951 952 putField(lf.type, lf.cpi, true); 953 } 954 955 958 public void putField(String fieldName, String fieldType) { 959 960 Type ft = cb.factory.type(fieldType); 961 int cpi = modClass.addFieldReference(cb.classType.vmNameSimple, fieldName, ft.vmName()); 962 963 putField(ft, cpi, true); 964 } 965 966 private void putField(Type fieldType, int cpi, boolean dup) { 967 968 if (dup) 970 { 971 myCode.addInstr(fieldType.width() == 2 ? VMOpcode.DUP2 : VMOpcode.DUP); 972 growStack(fieldType); 973 } 974 978 pushThis(); 979 983 swap(); 984 988 myCode.addInstrU2(VMOpcode.PUTFIELD, cpi); 989 popStack(); popStack(); 992 } 996 1000 public void putField(String declaringClass, String fieldName, String fieldType) { 1001 Type vt = popStack(); 1002 Type dt = popStack(); 1003 1004 if (SanityManager.DEBUG) { 1005 if (dt.width() != 1) 1006 SanityManager.THROWASSERT("reference expected for field access - is " + dt.javaName()); 1007 } 1008 1009 1012 myCode.addInstr(vt.width() == 2 ? VMOpcode.DUP2_X1 : VMOpcode.DUP_X1); 1013 growStack(vt); 1014 growStack(dt); 1015 growStack(vt); 1016 1017 Type dtu = vmNameDeclaringClass(declaringClass); 1018 if (dtu != null) 1019 dt = dtu; 1020 1021 Type ft = cb.factory.type(fieldType); 1022 int cpi = modClass.addFieldReference(dt.vmNameSimple, fieldName, ft.vmName()); 1023 myCode.addInstrU2(VMOpcode.PUTFIELD, cpi); 1024 1025 popStack(); popStack(); } 1028 1029 public void conditionalIfNull() { 1030 1031 conditionalIf(VMOpcode.IFNONNULL); 1032 } 1033 1034 public void conditionalIf() { 1035 conditionalIf(VMOpcode.IFEQ); 1036 } 1037 1038 private Conditional condition; 1039 1040 private void conditionalIf(short opcode) { 1041 popStack(); 1042 1043 1047 condition = new Conditional(condition, myCode, opcode, copyStack()); 1048 } 1049 1050 public void startElseCode() { 1051 1052 Type[] entryStack = condition.startElse(this, myCode, copyStack()); 1054 1055 for (int i = stackDepth = 0; i < entryStack.length; i++) 1056 { 1057 stackDepth += (stackTypes[i] = entryStack[i]).width(); 1058 } 1059 this.stackTypeOffset = entryStack.length; 1060 1061 } 1062 public void completeConditional() { 1063 condition = condition.end(this, myCode, stackTypes, stackTypeOffset); 1064 } 1065 1066 public void pop() { 1067 if (SanityManager.DEBUG) { 1068 if (stackDepth == 0) 1069 SanityManager.THROWASSERT("pop when stack is empty!"); 1070 } 1071 Type toPop = popStack(); 1072 1073 myCode.addInstr(toPop.width() == 2 ? VMOpcode.POP2 : VMOpcode.POP); 1074 1075 if (stackDepth == 0) 1076 overflowMethodCheck(); 1077 } 1078 1079 public void endStatement() { 1080 if (stackDepth != 0) { 1081 pop(); 1082 } 1083 1084 } 1089 1090 1092 public void getArrayElement(int element) { 1093 1094 push(element); 1095 popStack(); 1097 Type arrayType = popStack(); 1098 1099 String arrayJava = arrayType.javaName(); 1100 String componentString = arrayJava.substring(0,arrayJava.length()-2); 1101 1102 Type componentType = cb.factory.type(componentString); 1103 1104 short typ = componentType.vmType(); 1105 1106 if ((typ == BCExpr.vm_int) && (componentType.vmName().equals("Z"))) 1108 typ = BCExpr.vm_byte; 1109 myCode.addInstr(CodeChunk.ARRAY_ACCESS[typ]); 1110 1111 growStack(componentType); 1112 1113 } 1114 1116 public void setArrayElement(int element) { 1117 1118 1120 push(element); 1121 1122 swap(); 1124 1125 Type componentType = popStack(); popStack(); 1128 popStack(); 1130 short typ = componentType.vmType(); 1131 1132 if ((typ == BCExpr.vm_int) && (componentType.vmName().equals("Z"))) 1134 typ = BCExpr.vm_byte; 1135 1136 myCode.addInstr(CodeChunk.ARRAY_STORE[typ]); 1137 } 1138 1146 private static final byte newArrayElementTypeMap[] = { 8, 9, 10, 11, 6, 7, 5 }; 1147 static final byte T_BOOLEAN = 4; 1148 1154 public void pushNewArray(String className, int size) { 1155 1156 push(size); 1157 popStack(); 1159 Type elementType = cb.factory.type(className); 1160 1161 if (elementType.vmType() == BCExpr.vm_reference) { 1163 1164 1167 int cpi = modClass.addClassReference(elementType.javaName()); 1168 myCode.addInstrU2(VMOpcode.ANEWARRAY, cpi); 1170 } else { 1171 byte atype; 1172 1173 if (elementType.vmType() == BCExpr.vm_int && 1178 VMDescriptor.C_BOOLEAN == elementType.vmName().charAt(0)) 1179 atype = T_BOOLEAN; 1180 else 1181 atype = newArrayElementTypeMap[elementType.vmType()]; 1182 1183 1186 myCode.addInstrU1(VMOpcode.NEWARRAY, atype); 1187 } 1188 1189 growStack(1, cb.factory.type(className.concat("[]"))); 1191 } 1192 1193 1199 private void addInstrCPE(short opcode, int cpe) 1200 { 1201 if (cpe >= VMOpcode.MAX_CONSTANT_POOL_ENTRIES) 1202 cb.addLimitExceeded(this, "constant_pool_count", 1203 VMOpcode.MAX_CONSTANT_POOL_ENTRIES, cpe); 1204 1205 myCode.addInstrCPE(opcode, cpe); 1206 } 1207 1208 1219 public boolean statementNumHitLimit(int noStatementsAdded) 1220 { 1221 if (statementNum > 2048) { 1223 return true; 1224 } 1225 else 1226 { 1227 statementNum = statementNum + noStatementsAdded; 1228 return false; 1229 } 1230 } 1231 1232 1272 private void overflowMethodCheck() 1273 { 1274 if (handlingOverflow) 1275 return; 1276 1277 if (condition != null) 1279 return; 1280 1281 int currentCodeSize = myCode.getPC(); 1282 1283 if (currentCodeSize < 55000) 1292 return; 1293 1294 if (parameters != null) 1296 { 1297 if (parameters.length != 0) 1298 return; 1299 } 1300 1301 BCMethod subMethod = getNewSubMethod(myReturnType, false); 1302 1303 handlingOverflow = true; 1305 1306 callSubMethod(subMethod); 1309 1310 this.methodReturn(); 1312 this.complete(); 1313 1314 handlingOverflow = false; 1315 1316 1322 this.myEntry = subMethod.myEntry; 1323 this.myCode = subMethod.myCode; 1324 this.currentVarNum = subMethod.currentVarNum; 1325 this.statementNum = subMethod.statementNum; 1326 1327 this.stackTypes = subMethod.stackTypes; 1329 this.stackTypeOffset = subMethod.stackTypeOffset; 1330 this.maxStack = subMethod.maxStack; 1331 this.stackDepth = subMethod.stackDepth; 1332 } 1333 1334 1347 final BCMethod getNewSubMethod(String returnType, boolean withParameters) { 1348 int modifiers = myEntry.getModifier(); 1349 1350 modifiers &= ~(Modifier.PROTECTED | Modifier.PUBLIC); 1353 modifiers |= Modifier.PRIVATE; 1354 1355 String subMethodName = myName + "_s" 1356 + Integer.toString(subMethodCount++); 1357 BCMethod subMethod = (BCMethod) cb.newMethodBuilder(modifiers, 1358 returnType, subMethodName, withParameters ? parameterTypes 1359 : null); 1360 subMethod.thrownExceptions = this.thrownExceptions; 1361 1362 return subMethod; 1363 } 1364 1365 1369 final void callSubMethod(BCMethod subMethod) { 1370 short op; 1373 if ((myEntry.getModifier() & Modifier.STATIC) == 0) { 1374 op = VMOpcode.INVOKEVIRTUAL; 1375 this.pushThis(); 1376 } else { 1377 op = VMOpcode.INVOKESTATIC; 1378 } 1379 1380 int parameterCount = subMethod.parameters == null ? 0 1381 : subMethod.parameters.length; 1382 1383 for (int pi = 0; pi < parameterCount; pi++) 1385 this.getParameter(pi); 1386 1387 this.callMethod(op, modClass.getName(), subMethod.getName(), 1388 subMethod.myReturnType, parameterCount); 1389 } 1390} 1391 1392 | Popular Tags |