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

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