Main Page   Packages   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members  

MethodGen.java

00001 package de.fub.bytecode.generic;
00002 
00003 import de.fub.bytecode.Constants;
00004 import de.fub.bytecode.classfile.*;
00005 import java.util.*;
00006 
00007 /** 
00008  * Template class for building up a method. This is done by defining exception
00009  * handlers, adding thrown exceptions, local variables and attributes, whereas
00010  * the `LocalVariableTable' and `LineNumberTable' attributes will be set
00011  * automatically for the code. Use stripAttributes() if you don't like this.
00012  *
00013  * While generating code it may be necessary to insert NOP operations. You can
00014  * use the `removeNOPs' method to get rid off them.
00015  * The resulting method object can be obtained via the `getMethod()' method.
00016  *
00017  * @version $Id: MethodGen.java,v 1.1.1.1 2002/01/24 03:41:41 pserver Exp $
00018  * @author  <A HREF="http://www.inf.fu-berlin.de/~dahm">M. Dahm</A>
00019  * @author  <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A>
00020  * @see     InstructionList
00021  * @see     Method
00022  */
00023 public class MethodGen extends FieldGenOrMethodGen {
00024   private String          class_name;
00025   private Type[]          arg_types;
00026   private String[]        arg_names;
00027   private int             max_locals;
00028   private int             max_stack;
00029   private InstructionList il;
00030   private boolean         strip_attributes;
00031 
00032   private Vector          variable_vec    = new Vector();
00033   private Vector          line_number_vec = new Vector();
00034   private Vector          exception_vec   = new Vector();
00035   private Vector          throws_vec      = new Vector();
00036   private Vector          code_attrs_vec  = new Vector();
00037 
00038   static final class BranchTarget {
00039     InstructionHandle target;
00040     int               stackDepth;
00041         
00042     BranchTarget(InstructionHandle target, int stackDepth) {
00043       this.target = target;
00044       this.stackDepth = stackDepth;
00045     }
00046   }
00047     
00048   static final class BranchStack {
00049     Stack     branchTargets  = new Stack();
00050     Hashtable visitedTargets = new Hashtable();
00051 
00052     public void push(InstructionHandle target, int stackDepth) {
00053       if(visited(target))
00054     return;
00055 
00056       branchTargets.push(visit(target, stackDepth));
00057     }
00058         
00059     public BranchTarget pop() {
00060       if(!branchTargets.empty()) {
00061     BranchTarget bt = (BranchTarget) branchTargets.pop();
00062     return bt;
00063       }
00064 
00065       return null;
00066     }
00067         
00068     private final BranchTarget visit(InstructionHandle target, int stackDepth) {
00069       BranchTarget bt = new BranchTarget(target, stackDepth);
00070       visitedTargets.put(target, bt);
00071 
00072       return bt;
00073     }
00074         
00075     private final boolean visited(InstructionHandle target) {
00076       return (visitedTargets.get(target) != null);
00077     }
00078   }
00079 
00080   private Vector observers;
00081 
00082   /**
00083    * Declare method. If the method is non-static the constructor
00084    * automatically declares a local variable `$this' in slot 0. The
00085    * actual code is contained in the `il' parameter, which may further
00086    * manipulated by the user. But he must take care not to remove any
00087    * instruction (handles) that are still referenced from this object.
00088    *
00089    * For example one may not add a local variable and later remove the
00090    * instructions it refers to without causing havoc. It is safe
00091    * however if you remove that local variable, too.
00092    *
00093    * @param access_flags access qualifiers
00094    * @param return_type  method type
00095    * @param arg_types argument types
00096    * @param arg_names argument names (if this is null, default names will be provided
00097    * for them)
00098    * @param method_name name of method
00099    * @param class_name class name containing this method (may be null, if you don't care)
00100    * @param il instruction list associated with this method, may be null only for
00101    * abstract or native methods
00102    * @param cp constant pool
00103    */
00104   public MethodGen(int access_flags, Type return_type, Type[] arg_types,
00105            String[] arg_names, String method_name, String class_name,
00106            InstructionList il, ConstantPoolGen cp) {
00107     setAccessFlags(access_flags);
00108     setType(return_type);
00109     setArgTypes(arg_types);
00110     setArgNames(arg_names);
00111     setName(method_name);
00112     setClassName(class_name);
00113     setInstructionList(il);
00114     setConstantPool(cp);
00115 
00116     if((access_flags & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0) {
00117       InstructionHandle start = il.getStart();
00118       InstructionHandle end   = il.getEnd();
00119 
00120       /* Add local variables, namely the implicit `this' and the arguments
00121        */
00122       if(!isStatic() && (class_name != null)) // Instance method -> `this' is local var 0
00123     addLocalVariable("this", new ObjectType(class_name), start, end); // Valid from start to end
00124     
00125       if(arg_types != null) {
00126     int size = arg_types.length;
00127     
00128     if(arg_names != null) { // Names for variables provided?
00129       if(size != arg_names.length)
00130         throw new ClassGenException("Mismatch in argument array lengths: " +
00131                     size + " vs. " + arg_names.length);
00132     } else { // Give them dummy names
00133       arg_names = new String[size];
00134 
00135       for(int i=0; i < size; i++)
00136         arg_names[i] = "arg" + i;
00137     }
00138 
00139     for(int i=0; i < size; i++)
00140       addLocalVariable(arg_names[i], arg_types[i], start, end);
00141       }
00142     }
00143   }  
00144   /**
00145    * Instantiate from existing method.
00146    *
00147    * @param m method
00148    * @param class_name class name containing this method
00149    * @param cp constant pool (must contain the same entries as the method's constant pool)
00150    */
00151   public MethodGen(Method m, String class_name, ConstantPoolGen cp) {
00152     this(m.getAccessFlags(), Type.getReturnType(m.getSignature()),
00153      Type.getArgumentTypes(m.getSignature()), null /* may be overridden anyway */,
00154      m.getName(), class_name,
00155      ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0)?
00156      new InstructionList(m.getCode().getCode()) : null,
00157      cp);
00158 
00159     Attribute[] attributes = m.getAttributes();
00160     for(int i=0; i < attributes.length; i++) {
00161       Attribute a = attributes[i];
00162 
00163       if(a instanceof Code) {
00164     Code c = (Code)a;
00165     setMaxStack(c.getMaxStack());
00166     setMaxLocals(c.getMaxLocals());
00167     
00168     CodeException[] ces = c.getExceptionTable();
00169     
00170     if(ces != null) {
00171       for(int j=0; j < ces.length; j++) {
00172             CodeException ce     = ces[j];
00173             int           type   = ce.getCatchType();
00174             ObjectType    c_type = null;
00175         
00176         if(type > 0) // contains bla/blubb, but ObjectType() doesn't care
00177           c_type = new ObjectType(cp.getConstantPool().
00178                       getConstantString(type, Constants.CONSTANT_Class));
00179         int end_pc = ce.getEndPC();
00180         int length = m.getCode().getCode().length;
00181         
00182         if(length == end_pc) // May happen, because end_pc is exclusive
00183           end_pc = end_pc - il.getEnd().getInstruction().getLength();
00184 
00185         addExceptionHandler(il.findHandle(ce.getStartPC()), il.findHandle(end_pc),
00186                 il.findHandle(ce.getHandlerPC()), c_type);
00187       }
00188     }
00189 
00190     Attribute[] c_attributes = c.getAttributes();
00191     for(int j=0; j < c_attributes.length; j++) {
00192       a = c_attributes[j];
00193 
00194       if(a instanceof LineNumberTable) {
00195         LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable();
00196         for(int k=0; k < ln.length; k++) {
00197           LineNumber l = ln[k];
00198           addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber());
00199         }
00200       }
00201       else if(a instanceof LocalVariableTable) {
00202         LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable();
00203         for(int k=0; k < lv.length; k++) {
00204           LocalVariable     l     = lv[k];
00205           InstructionHandle start = il.findHandle(l.getStartPC());
00206           InstructionHandle end   = il.findHandle(l.getStartPC() + l.getLength());
00207 
00208           // Repair malformed handles
00209           if(start == null)
00210         start = il.getStart();
00211           if(end == null)
00212         end = il.getEnd();
00213 
00214           addLocalVariable(l.getName(), Type.getType(l.getSignature()),
00215                    l.getIndex(), start, end);
00216         }
00217       }
00218       else
00219         System.err.println("Unknown Code attribute " + a + " ignored.");
00220     }
00221       }
00222       else if(a instanceof ExceptionTable) {
00223     String[] names = ((ExceptionTable)a).getExceptionNames();
00224     for(int j=0; j < names.length; j++)
00225       addException(names[j]);
00226       }
00227       else
00228     addAttribute(a);
00229     }
00230   }  
00231   /**
00232    * Add an attribute to the code. Currently, the JVM knows about the `LineNumberTable' and
00233    * `LocalVariableTable' attributes, which will be generated automatically. Other attributes
00234    * will be ignored by the JVM but do no harm.
00235    *
00236    * @param a attribute to be added
00237    */
00238   public void addCodeAttribute(Attribute a) { code_attrs_vec.addElement(a); }  
00239   /**
00240    * Add an exception possibly thrown by this method.
00241    *
00242    * @param class_name (fully qualified) name of exception
00243    */
00244   public void addException(String class_name) {
00245     throws_vec.addElement(class_name);
00246   }  
00247   /**
00248    * Add an exception handler, i.e., specify region where a handler is active and an
00249    * instruction where the actual handling is done.
00250    *
00251    * @param start_pc Start of region
00252    * @param end_pc End of region
00253    * @param handler_pc Where handling is done
00254    * @param catch_type fully qualified class name of handled exception or null if any
00255    * exception is handled
00256    * @return new exception handler object
00257    */
00258   public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
00259                           InstructionHandle end_pc,
00260                           InstructionHandle handler_pc,
00261                           ObjectType catch_type) {
00262     if((start_pc == null) || (end_pc == null) || (handler_pc == null))
00263       throw new ClassGenException("Exception handler target is null instruction");
00264     
00265     CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc,
00266                           handler_pc, catch_type);
00267     exception_vec.addElement(c);
00268     return c;
00269   }  
00270   /**
00271    * @deprecated Use above method
00272    */
00273   public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
00274                           InstructionHandle end_pc,
00275                           InstructionHandle handler_pc,
00276                           String catch_type) {
00277     return addExceptionHandler(start_pc, end_pc, handler_pc, catch_type == null?
00278                    null : new ObjectType(catch_type));
00279   }  
00280   /**
00281    * Give an instruction a line number corresponding to the source code line.
00282    *
00283    * @param ih instruction to tag
00284    * @return new line number object
00285    * @see LineNumber
00286    */
00287   public LineNumberGen addLineNumber(InstructionHandle ih, int src_line) {
00288     LineNumberGen l = new LineNumberGen(ih, src_line);
00289     line_number_vec.addElement(l);
00290     return l;
00291   }  
00292   /**
00293    * Adds a local variable to this method.
00294    *
00295    * @param name variable name
00296    * @param type variable type
00297    * @param slot the index of the local variable, if type is long or double, the next available
00298    * index is slot+2
00299    * @param start from where the variable is valid
00300    * @param end until where the variable is valid
00301    * @return new local variable object
00302    * @see LocalVariable
00303    */
00304   public LocalVariableGen addLocalVariable(String name, Type type, int slot,
00305                        InstructionHandle start,
00306                        InstructionHandle end) {
00307     byte t   = type.getType();
00308     int  add = type.getSize();
00309     
00310     if(slot + add > max_locals) 
00311       max_locals = slot + add;
00312 
00313     LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
00314     int i;
00315 
00316     if((i = variable_vec.indexOf(l)) >= 0) // Overwrite if necessary
00317       variable_vec.setElementAt(l, i);
00318     else
00319       variable_vec.addElement(l);
00320     return l;
00321   }  
00322   /**
00323    * Adds a local variable to this method and assigns an index automatically.
00324    *
00325    * @param name variable name
00326    * @param type variable type
00327    * @param start from where the variable is valid, if this is null,
00328    * it is valid from the start
00329    * @param end until where the variable is valid, if this is null,
00330    * it is valid to the end
00331    * @return new local variable object
00332    * @see LocalVariable
00333    */
00334   public LocalVariableGen addLocalVariable(String name, Type type,
00335                        InstructionHandle start,
00336                        InstructionHandle end) {
00337     return addLocalVariable(name, type, max_locals, start, end);
00338   }  
00339   /** Add observer for this object.
00340    */
00341   public void addObserver(MethodObserver o) {
00342     if(observers == null)
00343       observers = new Vector();
00344 
00345     observers.add(o);
00346   }  
00347   public String   getArgName(int i)                  { return arg_names[i]; }  
00348   public String[] getArgNames()                      { return (String[])arg_names.clone(); }  
00349   public Type   getArgType(int i)                  { return arg_types[i]; }  
00350   public Type[] getArgTypes()                      { return (Type[])arg_types.clone(); }  
00351   /** @return class that contains this method
00352    */
00353   public String getClassName()                     { return class_name; }  
00354   /**
00355    * @return all attributes of this method.
00356    */
00357   public Attribute[] getCodeAttributes() {
00358     Attribute[] attributes = new Attribute[code_attrs_vec.size()];
00359     code_attrs_vec.copyInto(attributes);
00360     return attributes;
00361   }  
00362   /**
00363    * @return code exceptions for `Code' attribute
00364    */
00365   private CodeException[] getCodeExceptions() {
00366     int             size  = exception_vec.size(); 
00367     CodeException[] c_exc = new CodeException[size];
00368 
00369     try {
00370       for(int i=0; i < size; i++) {
00371     CodeExceptionGen c = (CodeExceptionGen)exception_vec.elementAt(i);
00372     c_exc[i] = c.getCodeException(cp);
00373       }
00374     } catch(ArrayIndexOutOfBoundsException e) {}
00375     
00376     return c_exc;
00377   }  
00378   /*
00379    * @return array of declared exception handlers
00380    */
00381   public CodeExceptionGen[] getExceptionHandlers() {
00382     CodeExceptionGen[] cg   = new CodeExceptionGen[exception_vec.size()];
00383     exception_vec.copyInto(cg);
00384     return cg;
00385   }  
00386   /*
00387    * @return array of thrown exceptions
00388    */
00389   public String[] getExceptions() {
00390     String[] e = new String[throws_vec.size()];
00391     throws_vec.copyInto(e);
00392     return e;
00393   }  
00394   /**
00395    * @return `Exceptions' attribute of all the exceptions thrown by this method.
00396    */
00397   private ExceptionTable getExceptionTable(ConstantPoolGen cp) {
00398     int   size = throws_vec.size();
00399     int[] ex   = new int[size];
00400       
00401     try {
00402       for(int i=0; i < size; i++)
00403     ex[i] = cp.addClass((String)throws_vec.elementAt(i));
00404     } catch(ArrayIndexOutOfBoundsException e) {}
00405     
00406     return new ExceptionTable(cp.addUtf8("Exceptions"),
00407                   2 + 2 * size, ex, cp.getConstantPool());
00408   }  
00409   public InstructionList getInstructionList()                    { return il; }  
00410   /*
00411    * @return array of line numbers
00412    */
00413   public LineNumberGen[] getLineNumbers() {
00414     LineNumberGen[] lg   = new LineNumberGen[line_number_vec.size()];
00415     line_number_vec.copyInto(lg);
00416     return lg;
00417   }  
00418   /**
00419    * @return `LineNumberTable' attribute of all the local variables of this method.
00420    */
00421   public LineNumberTable getLineNumberTable(ConstantPoolGen cp) {
00422     int          size = line_number_vec.size(); 
00423     LineNumber[] ln   = new LineNumber[size];
00424 
00425     try {
00426       for(int i=0; i < size; i++)
00427     ln[i] = ((LineNumberGen)line_number_vec.elementAt(i)).getLineNumber(cp);
00428     } catch(ArrayIndexOutOfBoundsException e) {} // Never occurs
00429 
00430     return new LineNumberTable(cp.addUtf8("LineNumberTable"),
00431                    2 + ln.length * 4, ln, cp.getConstantPool());
00432   }  
00433   /*
00434    * If the range of the variable has not been set yet, it will be set to be valid from
00435    * the start to the end of the instruction list.
00436    * 
00437    * @return array of declared local variables sorted by index
00438    */
00439   public LocalVariableGen[] getLocalVariables() {
00440     int                size = variable_vec.size();
00441     LocalVariableGen[] lg   = new LocalVariableGen[size];
00442     variable_vec.copyInto(lg);
00443     
00444     for(int i=0; i < size; i++) {
00445       if(lg[i].getStart() == null)
00446     lg[i].setStart(il.getStart());
00447 
00448       if(lg[i].getEnd() == null)
00449     lg[i].setEnd(il.getEnd());
00450     }
00451 
00452     if(size > 1)
00453       sort(lg, 0, size - 1);
00454 
00455     return lg;
00456   }  
00457   /**
00458    * @return `LocalVariableTable' attribute of all the local variables of this method.
00459    */
00460   public LocalVariableTable getLocalVariableTable(ConstantPoolGen cp) {
00461     LocalVariableGen[] lg   = getLocalVariables();
00462     int                size = lg.length;
00463     LocalVariable[]    lv   = new LocalVariable[size];
00464 
00465     for(int i=0; i < size; i++)
00466       lv[i] = lg[i].getLocalVariable(cp);
00467 
00468     return new LocalVariableTable(cp.addUtf8("LocalVariableTable"),
00469                   2 + lv.length * 10, lv, cp.getConstantPool());
00470   }  
00471   public int    getMaxLocals()       { return max_locals; }  
00472   public int    getMaxStack()       { return max_stack; }  
00473   /**
00474    * Computes stack usage of an instruction list by performing control flow analysis.
00475    *
00476    * @return maximum stack depth used by method
00477    */
00478   public static int getMaxStack(ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et) {
00479     BranchStack branchTargets = new BranchStack();
00480         
00481     /* Initially, populate the branch stack with the exception
00482      * handlers, because these aren't (necessarily) branched to
00483      * explicitly. in each case, the stack will have depth 1,
00484      * containing the exception object.
00485      */
00486     for (int i = 0; i < et.length; i++) {
00487       InstructionHandle handler_pc = et[i].getHandlerPC();
00488       if (handler_pc != null)
00489     branchTargets.push(handler_pc, 1);
00490     }
00491         
00492     int               stackDepth = 0, maxStackDepth = 0;
00493     InstructionHandle ih         = il.getStart();
00494 
00495     while(ih != null) {
00496       Instruction instruction = ih.getInstruction();
00497       short tag = instruction.getTag();
00498       int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
00499 
00500       stackDepth += delta;
00501       if(stackDepth > maxStackDepth)
00502     maxStackDepth = stackDepth;
00503 
00504       // choose the next instruction based on whether current is a branch.
00505       if(instruction instanceof BranchInstruction) {
00506     BranchInstruction branch = (BranchInstruction) instruction;
00507     if(instruction instanceof Select) {
00508       // explore all of the select's targets. the default target is handled below.
00509       Select select = (Select) branch;
00510       InstructionHandle[] targets = select.getTargets();
00511       for (int i = 0; i < targets.length; i++)
00512         branchTargets.push(targets[i], stackDepth);
00513       // nothing to fall through to.
00514       ih = null;
00515     } else if(!(branch instanceof IfInstruction)) {
00516       // if an instruction that comes back to following PC,
00517       // push next instruction, with stack depth reduced by 1.
00518       if(tag == Constants.JSR || tag == Constants.JSR_W)
00519         branchTargets.push(ih.getNext(), stackDepth - 1);
00520       ih = null;
00521     }
00522     // for all branches, the target of the branch is pushed on the branch stack.
00523     // conditional branches have a fall through case, selects don't, and
00524     // jsr/jsr_w return to the next instruction.
00525     branchTargets.push(branch.getTarget(), stackDepth);
00526       } else {
00527     // check for instructions that terminate the method.
00528     if(tag == Constants.ATHROW || tag == Constants.RET ||
00529        (tag >= Constants.IRETURN && tag <= Constants.RETURN))
00530       ih = null;
00531       }
00532       // normal case, go to the next instruction.
00533       if(ih != null)
00534     ih = ih.getNext();
00535       // if we have no more instructions, see if there are any deferred branches to explore.
00536       if(ih == null) {
00537     BranchTarget bt = branchTargets.pop();
00538     if (bt != null) {
00539       ih = bt.target;
00540       stackDepth = bt.stackDepth;
00541     }
00542       }
00543     }
00544 
00545     return maxStackDepth;
00546   }  
00547   /**
00548    * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively,
00549    * before calling this method. This method should be called exactly once when the buildup
00550    * is finished.
00551    *
00552    * @return method object
00553    */
00554   public Method getMethod() {
00555     String signature       = getSignature();
00556     int    name_index      = cp.addUtf8(name);
00557     int    signature_index = cp.addUtf8(signature);
00558 
00559     /* Also updates positions of instructions, i.e., their indices
00560      */
00561     byte[] byte_code = null;
00562 
00563     if(il != null)
00564       byte_code = il.getByteCode();
00565 
00566     /* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.)
00567      */
00568     if((variable_vec.size() > 0) && !strip_attributes)
00569       addCodeAttribute(getLocalVariableTable(cp));
00570 
00571     if((line_number_vec.size() > 0) && !strip_attributes)
00572       addCodeAttribute(getLineNumberTable(cp));
00573 
00574     Attribute[] code_attrs = getCodeAttributes();
00575 
00576     /* Each attribute causes 6 additional header bytes
00577      */
00578     int                attrs_len  = 0;
00579     for(int i=0; i < code_attrs.length; i++)
00580       attrs_len += (code_attrs[i].getLength() + 6);
00581 
00582     CodeException[] c_exc   = getCodeExceptions();
00583     int             exc_len = c_exc.length * 8; // Every entry takes 8 bytes
00584 
00585     if((il != null) && !isAbstract()) {
00586       Code code = new Code(cp.addUtf8("Code"),
00587                8 + byte_code.length + // prologue byte code
00588                2 + exc_len +          // exceptions
00589                2 + attrs_len,         // attributes
00590                max_stack, max_locals,
00591                byte_code, c_exc,
00592                code_attrs,
00593                cp.getConstantPool());
00594 
00595       addAttribute(code);
00596     }
00597     
00598     if(throws_vec.size() > 0)
00599       addAttribute(getExceptionTable(cp)); // Add `Exceptions' if there are "throws" clauses
00600 
00601     return new Method(access_flags, name_index, signature_index,
00602               getAttributes(), cp.getConstantPool());
00603   }  
00604   /**@deprecated Use setName()
00605    */
00606   public String getMethodName()                    { return getName(); }  
00607   /**@deprecated Use getSignature()
00608    */
00609   public String getMethodSignature() { 
00610     return getSignature();
00611   }  
00612   public Type   getReturnType()                    { return getType(); }  
00613   public String getSignature() { 
00614     return Type.getMethodSignature(type, arg_types);
00615   }  
00616   /**
00617    * Remove a code attribute.
00618    */
00619   public void removeCodeAttribute(Attribute a) { code_attrs_vec.removeElement(a); }  
00620   /**
00621    * Remove an exception.
00622    */
00623   public void removeException(String c) {
00624     throws_vec.removeElement(c);  
00625   }  
00626   /**
00627    * Remove an exception handler.
00628    */
00629   public void removeExceptionHandler(CodeExceptionGen c) {
00630     exception_vec.removeElement(c);  
00631   }  
00632   /**
00633    * Remove all line numbers.
00634    */
00635   public void removeExceptionHandlers() {
00636     exception_vec.clear();
00637   }  
00638   /**
00639    * Remove all exceptions.
00640    */
00641   public void removeExceptions() {
00642     throws_vec.clear();  
00643   }  
00644   /**
00645    * Remove a line number.
00646    */
00647   public void removeLineNumber(LineNumberGen l) {
00648     line_number_vec.removeElement(l);  
00649   }  
00650   /**
00651    * Remove all line numbers.
00652    */
00653   public void removeLineNumbers() {
00654     line_number_vec.clear();
00655   }  
00656   /**
00657    * Remove a local variable, its slot will not be reused, if you do not use addLocalVariable
00658    * with an explicit index argument.
00659    */
00660   public void removeLocalVariable(LocalVariableGen l) {
00661     variable_vec.removeElement(l);  
00662   }  
00663   /**
00664    * Remove all local variables.
00665    */
00666   public void removeLocalVariables() {
00667     variable_vec.clear();
00668   }  
00669   /**
00670    * Remove all NOPs from the instruction list (if possible) and update every
00671    * object refering to them, i.e., branch instructions, local variables and
00672    * exception handlers.
00673    */
00674   public void removeNOPs() {
00675     if(il != null) {
00676       InstructionHandle next;
00677       /* Check branch instructions.
00678        */
00679       for(InstructionHandle ih = il.getStart(); ih != null; ih = next) {
00680     next = ih.next;
00681 
00682     if((next != null) && (ih.getInstruction() instanceof NOP)) {
00683       try {
00684         il.delete(ih);
00685       } catch(TargetLostException e) {
00686         InstructionHandle[] targets = e.getTargets();
00687         
00688         for(int i=0; i < targets.length; i++) {
00689           InstructionTargeter[] targeters = targets[i].getTargeters();
00690           
00691           for(int j=0; j < targeters.length; j++)
00692         targeters[j].updateTarget(targets[i], next);
00693         }
00694       }
00695     }
00696       }
00697     }
00698   }  
00699   /** Remove observer for this object.
00700    */
00701   public void removeObserver(MethodObserver o) {
00702     if(observers != null)
00703       observers.removeElement(o);
00704   }  
00705   public void     setArgName(int i, String name)     { arg_names[i] = name; }  
00706   public void     setArgNames(String[] arg_names)    { this.arg_names = arg_names; }  
00707   public void   setArgType(int i, Type type)       { arg_types[i] = type; }  
00708   public void   setArgTypes(Type[] arg_types)      { this.arg_types = arg_types; }  
00709   public void   setClassName(String class_name)    { this.class_name = class_name; }  
00710   public void            setInstructionList(InstructionList il)  { this.il = il; }  
00711   /**
00712    * Compute maximum number of local variables. May be a little bit to large, but who cares ...
00713    */
00714   public void setMaxLocals() {
00715     if(il != null) {
00716       int max = 0;
00717       LocalVariableInstruction last_local = null;
00718 
00719       if(arg_types != null)
00720     for(int i=0; i < arg_types.length; i++)
00721       max += arg_types[i].getSize();
00722 
00723       for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
00724     Instruction ins = ih.getInstruction();
00725     if(ins instanceof LocalVariableInstruction) {
00726       LocalVariableInstruction local = (LocalVariableInstruction)ins;
00727       int index = local.getIndex() + local.getType(cp).getSize();
00728 
00729       if(index > max)
00730         max = index;
00731     }
00732       }
00733 
00734       max_locals = max; // double, long take two slots
00735     } else
00736       max_locals = 0;
00737   }  
00738   /**
00739    * Set maximum number of local variables.
00740    */
00741   public void   setMaxLocals(int m)  { max_locals = m; }  
00742   /**
00743    * Computes max. stack size by performing control flow analysis.
00744    * @author  <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A>
00745    */
00746   public void setMaxStack() {
00747     if(il != null)
00748       max_stack = getMaxStack(cp, il, getExceptionHandlers());
00749     else
00750       max_stack = 0;
00751   }  
00752   /**
00753    * Set maximum stack size for this method.
00754    */
00755   public void   setMaxStack(int m)  { max_stack = m; }  
00756   /**@deprecated Use getName()
00757    */
00758   public void   setMethodName(String method_name)  { setName(method_name); }  
00759   public void   setReturnType(Type return_type)    { setType(return_type); }  
00760   /**
00761    * Sort local variables by index
00762    */
00763   private static final void sort(LocalVariableGen[] vars, int l, int r) {
00764     int i = l, j = r;
00765     int m = vars[(l + r) / 2].getIndex();
00766     LocalVariableGen h;
00767 
00768     do {
00769       while(vars[i].getIndex() < m) i++;
00770       while(m < vars[j].getIndex()) j--;
00771 
00772       if(i <= j) {
00773         h=vars[i]; vars[i]=vars[j]; vars[j]=h; // Swap elements
00774         i++; j--;
00775       }
00776     } while(i <= j);
00777 
00778     if(l < j) sort(vars, l, j);
00779     if(i < r) sort(vars, i, r);
00780   }  
00781   /** Do not/Do produce attributes code attributesLineNumberTable and
00782    * LocalVariableTable, like javac -O
00783    */
00784   public void stripAttributes(boolean flag) { strip_attributes = flag; }  
00785   /**
00786    * Return string representation close to declaration format,
00787    * `public static int main(String[]) throws IOException', e.g.
00788    *
00789    * @return String representation of the method.
00790    */
00791   public final String toString() {
00792     String access    = Utility.accessToString(access_flags);
00793     String signature = Type.getMethodSignature(type, arg_types);
00794 
00795     signature = Utility.methodSignatureToString(signature, name, access);
00796 
00797     StringBuffer buf = new StringBuffer(signature);
00798 
00799     if(throws_vec.size() > 0) {
00800       for(Enumeration e = throws_vec.elements(); e.hasMoreElements(); )
00801     buf.append("\n\t\tthrows " + e.nextElement());
00802     }
00803  
00804     return buf.toString();
00805   }  
00806   /** Call notify() method on all observers. This method is not called
00807    * automatically whenever the state has changed, but has to be
00808    * called by the user after he has finished editing the object.
00809    */
00810   public void update() {
00811     if(observers != null)
00812       for(Enumeration e = observers.elements(); e.hasMoreElements(); )
00813     ((MethodObserver)e.nextElement()).notify(this);
00814   }  
00815 }

Generated at Thu Feb 7 06:50:24 2002 for Bandera by doxygen1.2.10 written by Dimitri van Heesch, © 1997-2001