1 package com.sun.org.apache.bcel.internal.generic; 2 3 56 57 import com.sun.org.apache.bcel.internal.Constants; 58 import com.sun.org.apache.bcel.internal.classfile.*; 59 import java.util.*; 60 61 77 public class MethodGen extends FieldGenOrMethodGen { 78 private String class_name; 79 private Type[] arg_types; 80 private String [] arg_names; 81 private int max_locals; 82 private int max_stack; 83 private InstructionList il; 84 private boolean strip_attributes; 85 86 private ArrayList variable_vec = new ArrayList(); 87 private ArrayList line_number_vec = new ArrayList(); 88 private ArrayList exception_vec = new ArrayList(); 89 private ArrayList throws_vec = new ArrayList(); 90 private ArrayList code_attrs_vec = new ArrayList(); 91 92 114 public MethodGen(int access_flags, Type return_type, Type[] arg_types, 115 String [] arg_names, String method_name, String class_name, 116 InstructionList il, ConstantPoolGen cp) { 117 setAccessFlags(access_flags); 118 setType(return_type); 119 setArgumentTypes(arg_types); 120 setArgumentNames(arg_names); 121 setName(method_name); 122 setClassName(class_name); 123 setInstructionList(il); 124 setConstantPool(cp); 125 126 if((access_flags & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0) { 127 InstructionHandle start = il.getStart(); 128 InstructionHandle end = il.getEnd(); 129 130 132 if(!isStatic() && (class_name != null)) addLocalVariable("this", new ObjectType(class_name), start, end); 134 135 if(arg_types != null) { 136 int size = arg_types.length; 137 138 if(arg_names != null) { if(size != arg_names.length) 140 throw new ClassGenException("Mismatch in argument array lengths: " + 141 size + " vs. " + arg_names.length); 142 } else { arg_names = new String [size]; 144 145 for(int i=0; i < size; i++) 146 arg_names[i] = "arg" + i; 147 148 setArgumentNames(arg_names); 149 } 150 151 for(int i=0; i < size; i++) 152 addLocalVariable(arg_names[i], arg_types[i], start, end); 153 } 154 } 155 } 156 157 164 public MethodGen(Method m, String class_name, ConstantPoolGen cp) { 165 this(m.getAccessFlags(), Type.getReturnType(m.getSignature()), 166 Type.getArgumentTypes(m.getSignature()), null , 167 m.getName(), class_name, 168 ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0)? 169 new InstructionList(m.getCode().getCode()) : null, 170 cp); 171 172 Attribute[] attributes = m.getAttributes(); 173 for(int i=0; i < attributes.length; i++) { 174 Attribute a = attributes[i]; 175 176 if(a instanceof Code) { 177 Code c = (Code)a; 178 setMaxStack(c.getMaxStack()); 179 setMaxLocals(c.getMaxLocals()); 180 181 CodeException[] ces = c.getExceptionTable(); 182 183 if(ces != null) { 184 for(int j=0; j < ces.length; j++) { 185 CodeException ce = ces[j]; 186 int type = ce.getCatchType(); 187 ObjectType c_type = null; 188 189 if(type > 0) { 190 String cen = m.getConstantPool().getConstantString(type, Constants.CONSTANT_Class); 191 c_type = new ObjectType(cen); 192 } 193 194 int end_pc = ce.getEndPC(); 195 int length = m.getCode().getCode().length; 196 197 InstructionHandle end; 198 199 if(length == end_pc) { end = il.getEnd(); 201 } else { 202 end = il.findHandle(end_pc); 203 end = end.getPrev(); } 205 206 addExceptionHandler(il.findHandle(ce.getStartPC()), end, 207 il.findHandle(ce.getHandlerPC()), c_type); 208 } 209 } 210 211 Attribute[] c_attributes = c.getAttributes(); 212 for(int j=0; j < c_attributes.length; j++) { 213 a = c_attributes[j]; 214 215 if(a instanceof LineNumberTable) { 216 LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable(); 217 for(int k=0; k < ln.length; k++) { 218 LineNumber l = ln[k]; 219 addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber()); 220 } 221 } else if(a instanceof LocalVariableTable) { 222 LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable(); 223 for(int k=0; k < lv.length; k++) { 224 LocalVariable l = lv[k]; 225 InstructionHandle start = il.findHandle(l.getStartPC()); 226 InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength()); 227 228 if(start == null) 230 start = il.getStart(); 231 if(end == null) 232 end = il.getEnd(); 233 234 addLocalVariable(l.getName(), Type.getType(l.getSignature()), 235 l.getIndex(), start, end); 236 } 237 } else 238 addCodeAttribute(a); 239 } 240 } else if(a instanceof ExceptionTable) { 241 String [] names = ((ExceptionTable)a).getExceptionNames(); 242 for(int j=0; j < names.length; j++) 243 addException(names[j]); 244 } else 245 addAttribute(a); 246 } 247 } 248 249 261 public LocalVariableGen addLocalVariable(String name, Type type, int slot, 262 InstructionHandle start, 263 InstructionHandle end) { 264 byte t = type.getType(); 265 int add = type.getSize(); 266 267 if(slot + add > max_locals) 268 max_locals = slot + add; 269 270 LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end); 271 int i; 272 273 if((i = variable_vec.indexOf(l)) >= 0) variable_vec.set(i, l); 275 else 276 variable_vec.add(l); 277 return l; 278 } 279 280 292 public LocalVariableGen addLocalVariable(String name, Type type, 293 InstructionHandle start, 294 InstructionHandle end) { 295 return addLocalVariable(name, type, max_locals, start, end); 296 } 297 298 302 public void removeLocalVariable(LocalVariableGen l) { 303 variable_vec.remove(l); 304 } 305 306 309 public void removeLocalVariables() { 310 variable_vec.clear(); 311 } 312 313 316 private static final void sort(LocalVariableGen[] vars, int l, int r) { 317 int i = l, j = r; 318 int m = vars[(l + r) / 2].getIndex(); 319 LocalVariableGen h; 320 321 do { 322 while(vars[i].getIndex() < m) i++; 323 while(m < vars[j].getIndex()) j--; 324 325 if(i <= j) { 326 h=vars[i]; vars[i]=vars[j]; vars[j]=h; i++; j--; 328 } 329 } while(i <= j); 330 331 if(l < j) sort(vars, l, j); 332 if(i < r) sort(vars, i, r); 333 } 334 335 341 public LocalVariableGen[] getLocalVariables() { 342 int size = variable_vec.size(); 343 LocalVariableGen[] lg = new LocalVariableGen[size]; 344 variable_vec.toArray(lg); 345 346 for(int i=0; i < size; i++) { 347 if(lg[i].getStart() == null) 348 lg[i].setStart(il.getStart()); 349 350 if(lg[i].getEnd() == null) 351 lg[i].setEnd(il.getEnd()); 352 } 353 354 if(size > 1) 355 sort(lg, 0, size - 1); 356 357 return lg; 358 } 359 360 363 public LocalVariableTable getLocalVariableTable(ConstantPoolGen cp) { 364 LocalVariableGen[] lg = getLocalVariables(); 365 int size = lg.length; 366 LocalVariable[] lv = new LocalVariable[size]; 367 368 for(int i=0; i < size; i++) 369 lv[i] = lg[i].getLocalVariable(cp); 370 371 return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 372 2 + lv.length * 10, lv, cp.getConstantPool()); 373 } 374 375 382 public LineNumberGen addLineNumber(InstructionHandle ih, int src_line) { 383 LineNumberGen l = new LineNumberGen(ih, src_line); 384 line_number_vec.add(l); 385 return l; 386 } 387 388 391 public void removeLineNumber(LineNumberGen l) { 392 line_number_vec.remove(l); 393 } 394 395 398 public void removeLineNumbers() { 399 line_number_vec.clear(); 400 } 401 402 405 public LineNumberGen[] getLineNumbers() { 406 LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()]; 407 line_number_vec.toArray(lg); 408 return lg; 409 } 410 411 414 public LineNumberTable getLineNumberTable(ConstantPoolGen cp) { 415 int size = line_number_vec.size(); 416 LineNumber[] ln = new LineNumber[size]; 417 418 try { 419 for(int i=0; i < size; i++) 420 ln[i] = ((LineNumberGen)line_number_vec.get(i)).getLineNumber(); 421 } catch(ArrayIndexOutOfBoundsException e) {} 423 return new LineNumberTable(cp.addUtf8("LineNumberTable"), 424 2 + ln.length * 4, ln, cp.getConstantPool()); 425 } 426 427 438 public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc, 439 InstructionHandle end_pc, 440 InstructionHandle handler_pc, 441 ObjectType catch_type) { 442 if((start_pc == null) || (end_pc == null) || (handler_pc == null)) 443 throw new ClassGenException("Exception handler target is null instruction"); 444 445 CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc, 446 handler_pc, catch_type); 447 exception_vec.add(c); 448 return c; 449 } 450 451 454 public void removeExceptionHandler(CodeExceptionGen c) { 455 exception_vec.remove(c); 456 } 457 458 461 public void removeExceptionHandlers() { 462 exception_vec.clear(); 463 } 464 465 468 public CodeExceptionGen[] getExceptionHandlers() { 469 CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()]; 470 exception_vec.toArray(cg); 471 return cg; 472 } 473 474 477 private CodeException[] getCodeExceptions() { 478 int size = exception_vec.size(); 479 CodeException[] c_exc = new CodeException[size]; 480 481 try { 482 for(int i=0; i < size; i++) { 483 CodeExceptionGen c = (CodeExceptionGen)exception_vec.get(i); 484 c_exc[i] = c.getCodeException(cp); 485 } 486 } catch(ArrayIndexOutOfBoundsException e) {} 487 488 return c_exc; 489 } 490 491 496 public void addException(String class_name) { 497 throws_vec.add(class_name); 498 } 499 500 503 public void removeException(String c) { 504 throws_vec.remove(c); 505 } 506 507 510 public void removeExceptions() { 511 throws_vec.clear(); 512 } 513 514 517 public String [] getExceptions() { 518 String [] e = new String [throws_vec.size()]; 519 throws_vec.toArray(e); 520 return e; 521 } 522 523 526 private ExceptionTable getExceptionTable(ConstantPoolGen cp) { 527 int size = throws_vec.size(); 528 int[] ex = new int[size]; 529 530 try { 531 for(int i=0; i < size; i++) 532 ex[i] = cp.addClass((String )throws_vec.get(i)); 533 } catch(ArrayIndexOutOfBoundsException e) {} 534 535 return new ExceptionTable(cp.addUtf8("Exceptions"), 536 2 + 2 * size, ex, cp.getConstantPool()); 537 } 538 539 548 public void addCodeAttribute(Attribute a) { code_attrs_vec.add(a); } 549 550 553 public void removeCodeAttribute(Attribute a) { code_attrs_vec.remove(a); } 554 555 558 public void removeCodeAttributes() { 559 code_attrs_vec.clear(); 560 } 561 562 565 public Attribute[] getCodeAttributes() { 566 Attribute[] attributes = new Attribute[code_attrs_vec.size()]; 567 code_attrs_vec.toArray(attributes); 568 return attributes; 569 } 570 571 577 public Method getMethod() { 578 String signature = getSignature(); 579 int name_index = cp.addUtf8(name); 580 int signature_index = cp.addUtf8(signature); 581 582 584 byte[] byte_code = null; 585 586 if(il != null) 587 byte_code = il.getByteCode(); 588 589 590 LineNumberTable lnt = null; 591 LocalVariableTable lvt = null; 592 593 595 if((variable_vec.size() > 0) && !strip_attributes) 596 addCodeAttribute(lvt = getLocalVariableTable(cp)); 597 598 if((line_number_vec.size() > 0) && !strip_attributes) 599 addCodeAttribute(lnt = getLineNumberTable(cp)); 600 601 Attribute[] code_attrs = getCodeAttributes(); 602 603 605 int attrs_len = 0; 606 for(int i=0; i < code_attrs.length; i++) 607 attrs_len += (code_attrs[i].getLength() + 6); 608 609 CodeException[] c_exc = getCodeExceptions(); 610 int exc_len = c_exc.length * 8; 612 Code code = null; 613 if((il != null) && !isAbstract()) { 614 code = new Code(cp.addUtf8("Code"), 615 8 + byte_code.length + 2 + exc_len + 2 + attrs_len, max_stack, max_locals, 619 byte_code, c_exc, 620 code_attrs, 621 cp.getConstantPool()); 622 623 addAttribute(code); 624 } 625 626 ExceptionTable et = null; 627 628 if(throws_vec.size() > 0) 629 addAttribute(et = getExceptionTable(cp)); 631 Method m = new Method(access_flags, name_index, signature_index, 632 getAttributes(), cp.getConstantPool()); 633 634 if(lvt != null) removeCodeAttribute(lvt); 636 if(lnt != null) removeCodeAttribute(lnt); 637 if(code != null) removeAttribute(code); 638 if(et != null) removeAttribute(et); 639 640 return m; 641 } 642 643 648 public void removeNOPs() { 649 if(il != null) { 650 InstructionHandle next; 651 653 for(InstructionHandle ih = il.getStart(); ih != null; ih = next) { 654 next = ih.next; 655 656 if((next != null) && (ih.getInstruction() instanceof NOP)) { 657 try { 658 il.delete(ih); 659 } catch(TargetLostException e) { 660 InstructionHandle[] targets = e.getTargets(); 661 662 for(int i=0; i < targets.length; i++) { 663 InstructionTargeter[] targeters = targets[i].getTargeters(); 664 665 for(int j=0; j < targeters.length; j++) 666 targeters[j].updateTarget(targets[i], next); 667 } 668 } 669 } 670 } 671 } 672 } 673 674 677 public void setMaxLocals(int m) { max_locals = m; } 678 public int getMaxLocals() { return max_locals; } 679 680 683 public void setMaxStack(int m) { max_stack = m; } 684 public int getMaxStack() { return max_stack; } 685 686 688 public String getClassName() { return class_name; } 689 public void setClassName(String class_name) { this.class_name = class_name; } 690 691 public void setReturnType(Type return_type) { setType(return_type); } 692 public Type getReturnType() { return getType(); } 693 694 public void setArgumentTypes(Type[] arg_types) { this.arg_types = arg_types; } 695 public Type[] getArgumentTypes() { return (Type[])arg_types.clone(); } 696 public void setArgumentType(int i, Type type) { arg_types[i] = type; } 697 public Type getArgumentType(int i) { return arg_types[i]; } 698 699 public void setArgumentNames(String [] arg_names) { this.arg_names = arg_names; } 700 public String [] getArgumentNames() { return (String [])arg_names.clone(); } 701 public void setArgumentName(int i, String name) { arg_names[i] = name; } 702 public String getArgumentName(int i) { return arg_names[i]; } 703 704 public InstructionList getInstructionList() { return il; } 705 public void setInstructionList(InstructionList il) { this.il = il; } 706 707 public String getSignature() { 708 return Type.getMethodSignature(type, arg_types); 709 } 710 711 715 public void setMaxStack() { 716 if(il != null) 717 max_stack = getMaxStack(cp, il, getExceptionHandlers()); 718 else 719 max_stack = 0; 720 } 721 722 725 public void setMaxLocals() { 726 if(il != null) { 727 int max = isStatic()? 0 : 1; 728 729 if(arg_types != null) 730 for(int i=0; i < arg_types.length; i++) 731 max += arg_types[i].getSize(); 732 733 for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) { 734 Instruction ins = ih.getInstruction(); 735 736 if((ins instanceof LocalVariableInstruction) || 737 (ins instanceof RET) || (ins instanceof IINC)) 738 { 739 int index = ((IndexedInstruction)ins).getIndex() + 740 ((TypedInstruction)ins).getType(cp).getSize(); 741 742 if(index > max) 743 max = index; 744 } 745 } 746 747 max_locals = max; 748 } else 749 max_locals = 0; 750 } 751 752 755 public void stripAttributes(boolean flag) { strip_attributes = flag; } 756 757 static final class BranchTarget { 758 InstructionHandle target; 759 int stackDepth; 760 761 BranchTarget(InstructionHandle target, int stackDepth) { 762 this.target = target; 763 this.stackDepth = stackDepth; 764 } 765 } 766 767 static final class BranchStack { 768 Stack branchTargets = new Stack(); 769 Hashtable visitedTargets = new Hashtable(); 770 771 public void push(InstructionHandle target, int stackDepth) { 772 if(visited(target)) 773 return; 774 775 branchTargets.push(visit(target, stackDepth)); 776 } 777 778 public BranchTarget pop() { 779 if(!branchTargets.empty()) { 780 BranchTarget bt = (BranchTarget) branchTargets.pop(); 781 return bt; 782 } 783 784 return null; 785 } 786 787 private final BranchTarget visit(InstructionHandle target, int stackDepth) { 788 BranchTarget bt = new BranchTarget(target, stackDepth); 789 visitedTargets.put(target, bt); 790 791 return bt; 792 } 793 794 private final boolean visited(InstructionHandle target) { 795 return (visitedTargets.get(target) != null); 796 } 797 } 798 799 804 public static int getMaxStack(ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et) { 805 BranchStack branchTargets = new BranchStack(); 806 807 812 for (int i = 0; i < et.length; i++) { 813 InstructionHandle handler_pc = et[i].getHandlerPC(); 814 if (handler_pc != null) 815 branchTargets.push(handler_pc, 1); 816 } 817 818 int stackDepth = 0, maxStackDepth = 0; 819 InstructionHandle ih = il.getStart(); 820 821 while(ih != null) { 822 Instruction instruction = ih.getInstruction(); 823 short opcode = instruction.getOpcode(); 824 int delta = instruction.produceStack(cp) - instruction.consumeStack(cp); 825 826 stackDepth += delta; 827 if(stackDepth > maxStackDepth) 828 maxStackDepth = stackDepth; 829 830 if(instruction instanceof BranchInstruction) { 832 BranchInstruction branch = (BranchInstruction) instruction; 833 if(instruction instanceof Select) { 834 Select select = (Select) branch; 836 InstructionHandle[] targets = select.getTargets(); 837 for (int i = 0; i < targets.length; i++) 838 branchTargets.push(targets[i], stackDepth); 839 ih = null; 841 } else if(!(branch instanceof IfInstruction)) { 842 if(opcode == Constants.JSR || opcode == Constants.JSR_W) 845 branchTargets.push(ih.getNext(), stackDepth - 1); 846 ih = null; 847 } 848 branchTargets.push(branch.getTarget(), stackDepth); 852 } else { 853 if(opcode == Constants.ATHROW || opcode == Constants.RET || 855 (opcode >= Constants.IRETURN && opcode <= Constants.RETURN)) 856 ih = null; 857 } 858 if(ih != null) 860 ih = ih.getNext(); 861 if(ih == null) { 863 BranchTarget bt = branchTargets.pop(); 864 if (bt != null) { 865 ih = bt.target; 866 stackDepth = bt.stackDepth; 867 } 868 } 869 } 870 871 return maxStackDepth; 872 } 873 874 private ArrayList observers; 875 876 878 public void addObserver(MethodObserver o) { 879 if(observers == null) 880 observers = new ArrayList(); 881 882 observers.add(o); 883 } 884 885 887 public void removeObserver(MethodObserver o) { 888 if(observers != null) 889 observers.remove(o); 890 } 891 892 896 public void update() { 897 if(observers != null) 898 for(Iterator e = observers.iterator(); e.hasNext(); ) 899 ((MethodObserver)e.next()).notify(this); 900 } 901 902 908 public final String toString() { 909 String access = Utility.accessToString(access_flags); 910 String signature = Type.getMethodSignature(type, arg_types); 911 912 signature = Utility.methodSignatureToString(signature, name, access, 913 true, getLocalVariableTable(cp)); 914 915 StringBuffer buf = new StringBuffer (signature); 916 917 if(throws_vec.size() > 0) { 918 for(Iterator e = throws_vec.iterator(); e.hasNext(); ) 919 buf.append("\n\t\tthrows " + e.next()); 920 } 921 922 return buf.toString(); 923 } 924 925 927 public MethodGen copy(String class_name, ConstantPoolGen cp) { 928 Method m = ((MethodGen)clone()).getMethod(); 929 MethodGen mg = new MethodGen(m, class_name, this.cp); 930 931 if(this.cp != cp) { 932 mg.setConstantPool(cp); 933 mg.getInstructionList().replaceConstantPool(this.cp, cp); 934 } 935 936 return mg; 937 } 938 } 939 | Popular Tags |