FileDocCategorySizeDatePackage
MethodGen.javaAPI DocJava SE 6 API30520Tue Jun 10 00:22:22 BST 2008com.sun.org.apache.bcel.internal.generic

MethodGen

public class MethodGen extends FieldGenOrMethodGen
Template class for building up a method. This is done by defining exception handlers, adding thrown exceptions, local variables and attributes, whereas the `LocalVariableTable' and `LineNumberTable' attributes will be set automatically for the code. Use stripAttributes() if you don't like this. While generating code it may be necessary to insert NOP operations. You can use the `removeNOPs' method to get rid off them. The resulting method object can be obtained via the `getMethod()' method.
version
$Id: MethodGen.java,v 1.1.2.1 2005/07/31 23:45:36 jeffsuttor Exp $
author
M. Dahm
author
Patrick C. Beard [setMaxStack()]
see
InstructionList
see
Method

Fields Summary
private String
class_name
private Type[]
arg_types
private String[]
arg_names
private int
max_locals
private int
max_stack
private InstructionList
il
private boolean
strip_attributes
private ArrayList
variable_vec
private ArrayList
line_number_vec
private ArrayList
exception_vec
private ArrayList
throws_vec
private ArrayList
code_attrs_vec
private ArrayList
observers
Constructors Summary
public MethodGen(int access_flags, Type return_type, Type[] arg_types, String[] arg_names, String method_name, String class_name, InstructionList il, ConstantPoolGen cp)
Declare method. If the method is non-static the constructor automatically declares a local variable `$this' in slot 0. The actual code is contained in the `il' parameter, which may further manipulated by the user. But he must take care not to remove any instruction (handles) that are still referenced from this object. For example one may not add a local variable and later remove the instructions it refers to without causing havoc. It is safe however if you remove that local variable, too.

param
access_flags access qualifiers
param
return_type method type
param
arg_types argument types
param
arg_names argument names (if this is null, default names will be provided for them)
param
method_name name of method
param
class_name class name containing this method (may be null, if you don't care)
param
il instruction list associated with this method, may be null only for abstract or native methods
param
cp constant pool


                                                                                                                                                            
        
		        
		       
    setAccessFlags(access_flags);
    setType(return_type);
    setArgumentTypes(arg_types);
    setArgumentNames(arg_names);
    setName(method_name);
    setClassName(class_name);
    setInstructionList(il);
    setConstantPool(cp);

    boolean abstract_ = isAbstract() || isNative();
    InstructionHandle start = null;
    InstructionHandle end   = null;

    if(!abstract_) {
      start = il.getStart();
      end   = il.getEnd();

      /* Add local variables, namely the implicit `this' and the arguments
       */
      if(!isStatic() && (class_name != null)) { // Instance method -> `this' is local var 0
	addLocalVariable("this", new ObjectType(class_name), start, end);
      }
    }

    if(arg_types != null) {
      int size = arg_types.length;

      for(int i=0; i < size; i++) {
	if(Type.VOID == arg_types[i]) {
	  throw new ClassGenException("'void' is an illegal argument type for a method");
	}
      }
	
      if(arg_names != null) { // Names for variables provided?
	if(size != arg_names.length)
	  throw new ClassGenException("Mismatch in argument array lengths: " +
				      size + " vs. " + arg_names.length);
      } else { // Give them dummy names
	arg_names = new String[size];
	
	for(int i=0; i < size; i++)
	  arg_names[i] = "arg" + i;
	
	setArgumentNames(arg_names);
      }
      
      if(!abstract_) {
	for(int i=0; i < size; i++) {
	  addLocalVariable(arg_names[i], arg_types[i], start, end);
	}
      }
    }
  
public MethodGen(Method m, String class_name, ConstantPoolGen cp)
Instantiate from existing method.

param
m method
param
class_name class name containing this method
param
cp constant pool

    this(m.getAccessFlags(), Type.getReturnType(m.getSignature()),
	 Type.getArgumentTypes(m.getSignature()), null /* may be overridden anyway */,
	 m.getName(), class_name,
	 ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0)?
	 new InstructionList(m.getCode().getCode()) : null,
	 cp);

    Attribute[] attributes = m.getAttributes();
    for(int i=0; i < attributes.length; i++) {
      Attribute a = attributes[i];

      if(a instanceof Code) {
	Code c = (Code)a;
	setMaxStack(c.getMaxStack());
	setMaxLocals(c.getMaxLocals());
	
	CodeException[] ces = c.getExceptionTable();
	
	if(ces != null) {
	  for(int j=0; j < ces.length; j++) {
            CodeException ce     = ces[j];
            int           type   = ce.getCatchType();
            ObjectType    c_type = null;

	    if(type > 0) {
	      String cen = m.getConstantPool().getConstantString(type, Constants.CONSTANT_Class);
	      c_type = new ObjectType(cen);
	    }

	    int end_pc = ce.getEndPC();
	    int length = m.getCode().getCode().length;
	    
	    InstructionHandle end;

	    if(length == end_pc) { // May happen, because end_pc is exclusive
	      end = il.getEnd();
	    } else {
	      end = il.findHandle(end_pc);
	      end = end.getPrev(); // Make it inclusive
	    }

	    addExceptionHandler(il.findHandle(ce.getStartPC()), end,
				il.findHandle(ce.getHandlerPC()), c_type);
	  }
	}

	Attribute[] c_attributes = c.getAttributes();
	for(int j=0; j < c_attributes.length; j++) {
	  a = c_attributes[j];

	  if(a instanceof LineNumberTable) {
	    LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable();

	    for(int k=0; k < ln.length; k++) {
	      LineNumber l = ln[k];
	      addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber());
	    }
	  } else if(a instanceof LocalVariableTable) {
	    LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable();

	    removeLocalVariables();

	    for(int k=0; k < lv.length; k++) {
	      LocalVariable     l     = lv[k];
	      InstructionHandle start = il.findHandle(l.getStartPC());
	      InstructionHandle end   = il.findHandle(l.getStartPC() + l.getLength());

	      // Repair malformed handles
	      if(null == start) {
		start = il.getStart();
	      }

	      if(null == end) {
		end = il.getEnd();
	      }

	      addLocalVariable(l.getName(), Type.getType(l.getSignature()),
			       l.getIndex(), start, end);
	    }
	  } else
	    addCodeAttribute(a);
	}
      } else if(a instanceof ExceptionTable) {
	String[] names = ((ExceptionTable)a).getExceptionNames();
	for(int j=0; j < names.length; j++)
	  addException(names[j]);
      } else
	addAttribute(a);
    }
  
Methods Summary
public voidaddCodeAttribute(com.sun.org.apache.bcel.internal.classfile.Attribute a)
Add an attribute to the code. Currently, the JVM knows about the LineNumberTable, LocalVariableTable and StackMap attributes, where the former two will be generated automatically and the latter is used for the MIDP only. Other attributes will be ignored by the JVM but do no harm.

param
a attribute to be added

 code_attrs_vec.add(a); 
public voidaddException(java.lang.String class_name)
Add an exception possibly thrown by this method.

param
class_name (fully qualified) name of exception

    throws_vec.add(class_name);
  
public com.sun.org.apache.bcel.internal.generic.CodeExceptionGenaddExceptionHandler(com.sun.org.apache.bcel.internal.generic.InstructionHandle start_pc, com.sun.org.apache.bcel.internal.generic.InstructionHandle end_pc, com.sun.org.apache.bcel.internal.generic.InstructionHandle handler_pc, com.sun.org.apache.bcel.internal.generic.ObjectType catch_type)
Add an exception handler, i.e., specify region where a handler is active and an instruction where the actual handling is done.

param
start_pc Start of region (inclusive)
param
end_pc End of region (inclusive)
param
handler_pc Where handling is done
param
catch_type class type of handled exception or null if any exception is handled
return
new exception handler object

    if((start_pc == null) || (end_pc == null) || (handler_pc == null))
      throw new ClassGenException("Exception handler target is null instruction");
    
    CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc,
					      handler_pc, catch_type);
    exception_vec.add(c);
    return c;
  
public com.sun.org.apache.bcel.internal.generic.LineNumberGenaddLineNumber(com.sun.org.apache.bcel.internal.generic.InstructionHandle ih, int src_line)
Give an instruction a line number corresponding to the source code line.

param
ih instruction to tag
return
new line number object
see
LineNumber

    LineNumberGen l = new LineNumberGen(ih, src_line);
    line_number_vec.add(l);
    return l;
  
public com.sun.org.apache.bcel.internal.generic.LocalVariableGenaddLocalVariable(java.lang.String name, com.sun.org.apache.bcel.internal.generic.Type type, int slot, com.sun.org.apache.bcel.internal.generic.InstructionHandle start, com.sun.org.apache.bcel.internal.generic.InstructionHandle end)
Adds a local variable to this method.

param
name variable name
param
type variable type
param
slot the index of the local variable, if type is long or double, the next available index is slot+2
param
start from where the variable is valid
param
end until where the variable is valid
return
new local variable object
see
LocalVariable

    byte t = type.getType();

    if(t != Constants.T_ADDRESS) {
      int  add = type.getSize();
    
      if(slot + add > max_locals) 
	max_locals = slot + add;
      
      LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
      int i;
      
      if((i = variable_vec.indexOf(l)) >= 0) // Overwrite if necessary
	variable_vec.set(i, l);
      else
	variable_vec.add(l);

      return l;
    } else {
      throw new IllegalArgumentException("Can not use " + type + 
					 " as type for local variable");
					 
    }
  
public com.sun.org.apache.bcel.internal.generic.LocalVariableGenaddLocalVariable(java.lang.String name, com.sun.org.apache.bcel.internal.generic.Type type, com.sun.org.apache.bcel.internal.generic.InstructionHandle start, com.sun.org.apache.bcel.internal.generic.InstructionHandle end)
Adds a local variable to this method and assigns an index automatically.

param
name variable name
param
type variable type
param
start from where the variable is valid, if this is null, it is valid from the start
param
end until where the variable is valid, if this is null, it is valid to the end
return
new local variable object
see
LocalVariable

    return addLocalVariable(name, type, max_locals, start, end);
  
public voidaddObserver(com.sun.org.apache.bcel.internal.generic.MethodObserver o)
Add observer for this object.

    if(observers == null)
      observers = new ArrayList();

    observers.add(o);
  
public com.sun.org.apache.bcel.internal.generic.MethodGencopy(java.lang.String class_name, com.sun.org.apache.bcel.internal.generic.ConstantPoolGen cp)

return
deep copy of this method

    Method    m  = ((MethodGen)clone()).getMethod();
    MethodGen mg = new MethodGen(m, class_name, this.cp);

    if(this.cp != cp) {
      mg.setConstantPool(cp);
      mg.getInstructionList().replaceConstantPool(this.cp, cp);
    }

    return mg;
  
public java.lang.StringgetArgumentName(int i)

 return arg_names[i]; 
public java.lang.String[]getArgumentNames()

 return (String[])arg_names.clone(); 
public com.sun.org.apache.bcel.internal.generic.TypegetArgumentType(int i)

 return arg_types[i]; 
public com.sun.org.apache.bcel.internal.generic.Type[]getArgumentTypes()

 return (Type[])arg_types.clone(); 
public java.lang.StringgetClassName()

return
class that contains this method

 return class_name; 
public com.sun.org.apache.bcel.internal.classfile.Attribute[]getCodeAttributes()

return
all attributes of this method.

    Attribute[] attributes = new Attribute[code_attrs_vec.size()];
    code_attrs_vec.toArray(attributes);
    return attributes;
  
private com.sun.org.apache.bcel.internal.classfile.CodeException[]getCodeExceptions()

return
code exceptions for `Code' attribute

    int             size  = exception_vec.size(); 
    CodeException[] c_exc = new CodeException[size];

    try {
      for(int i=0; i < size; i++) {
	CodeExceptionGen c = (CodeExceptionGen)exception_vec.get(i);
	c_exc[i] = c.getCodeException(cp);
      }
    } catch(ArrayIndexOutOfBoundsException e) {}
    
    return c_exc;
  
public com.sun.org.apache.bcel.internal.generic.CodeExceptionGen[]getExceptionHandlers()

    CodeExceptionGen[] cg   = new CodeExceptionGen[exception_vec.size()];
    exception_vec.toArray(cg);
    return cg;
  
private com.sun.org.apache.bcel.internal.classfile.ExceptionTablegetExceptionTable(com.sun.org.apache.bcel.internal.generic.ConstantPoolGen cp)

return
`Exceptions' attribute of all the exceptions thrown by this method.

    int   size = throws_vec.size();
    int[] ex   = new int[size];
      
    try {
      for(int i=0; i < size; i++)
	ex[i] = cp.addClass((String)throws_vec.get(i));
    } catch(ArrayIndexOutOfBoundsException e) {}
    
    return new ExceptionTable(cp.addUtf8("Exceptions"),
			      2 + 2 * size, ex, cp.getConstantPool());
  
public java.lang.String[]getExceptions()

    String[] e = new String[throws_vec.size()];
    throws_vec.toArray(e);
    return e;
  
public com.sun.org.apache.bcel.internal.generic.InstructionListgetInstructionList()

 return il; 
public com.sun.org.apache.bcel.internal.classfile.LineNumberTablegetLineNumberTable(com.sun.org.apache.bcel.internal.generic.ConstantPoolGen cp)

return
`LineNumberTable' attribute of all the local variables of this method.

    int          size = line_number_vec.size(); 
    LineNumber[] ln   = new LineNumber[size];

    try {
      for(int i=0; i < size; i++)
	ln[i] = ((LineNumberGen)line_number_vec.get(i)).getLineNumber();
    } catch(ArrayIndexOutOfBoundsException e) {} // Never occurs

    return new LineNumberTable(cp.addUtf8("LineNumberTable"),
			       2 + ln.length * 4, ln, cp.getConstantPool());
  
public com.sun.org.apache.bcel.internal.generic.LineNumberGen[]getLineNumbers()

    LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()];
    line_number_vec.toArray(lg);
    return lg;
  
public com.sun.org.apache.bcel.internal.classfile.LocalVariableTablegetLocalVariableTable(com.sun.org.apache.bcel.internal.generic.ConstantPoolGen cp)

return
`LocalVariableTable' attribute of all the local variables of this method.

    LocalVariableGen[] lg   = getLocalVariables();
    int                size = lg.length;
    LocalVariable[]    lv   = new LocalVariable[size];

    for(int i=0; i < size; i++)
      lv[i] = lg[i].getLocalVariable(cp);

    return new LocalVariableTable(cp.addUtf8("LocalVariableTable"),
				  2 + lv.length * 10, lv, cp.getConstantPool());
  
public com.sun.org.apache.bcel.internal.generic.LocalVariableGen[]getLocalVariables()

    int                size = variable_vec.size();
    LocalVariableGen[] lg   = new LocalVariableGen[size];
    variable_vec.toArray(lg);
    
    for(int i=0; i < size; i++) {
      if(lg[i].getStart() == null)
	lg[i].setStart(il.getStart());

      if(lg[i].getEnd() == null)
	lg[i].setEnd(il.getEnd());
    }

    if(size > 1)
      sort(lg, 0, size - 1);

    return lg;
  
public intgetMaxLocals()

 return max_locals; 
public intgetMaxStack()

 return max_stack; 
public static intgetMaxStack(com.sun.org.apache.bcel.internal.generic.ConstantPoolGen cp, com.sun.org.apache.bcel.internal.generic.InstructionList il, com.sun.org.apache.bcel.internal.generic.CodeExceptionGen[] et)
Computes stack usage of an instruction list by performing control flow analysis.

return
maximum stack depth used by method

    BranchStack branchTargets = new BranchStack();
    	
    /* Initially, populate the branch stack with the exception
     * handlers, because these aren't (necessarily) branched to
     * explicitly. in each case, the stack will have depth 1,
     * containing the exception object.
     */
    for (int i = 0; i < et.length; i++) {
      InstructionHandle handler_pc = et[i].getHandlerPC();
      if (handler_pc != null)
	branchTargets.push(handler_pc, 1);
    }
    	
    int               stackDepth = 0, maxStackDepth = 0;
    InstructionHandle ih         = il.getStart();

    while(ih != null) {
      Instruction instruction = ih.getInstruction();
      short opcode = instruction.getOpcode();
      int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);

      stackDepth += delta;
      if(stackDepth > maxStackDepth)
	maxStackDepth = stackDepth;

      // choose the next instruction based on whether current is a branch.
      if(instruction instanceof BranchInstruction) {
	BranchInstruction branch = (BranchInstruction) instruction;
	if(instruction instanceof Select) {
	  // explore all of the select's targets. the default target is handled below.
	  Select select = (Select) branch;
	  InstructionHandle[] targets = select.getTargets();
	  for (int i = 0; i < targets.length; i++)
	    branchTargets.push(targets[i], stackDepth);
	  // nothing to fall through to.
	  ih = null;
	} else if(!(branch instanceof IfInstruction)) {
	  // if an instruction that comes back to following PC,
	  // push next instruction, with stack depth reduced by 1.
	  if(opcode == Constants.JSR || opcode == Constants.JSR_W)
	    branchTargets.push(ih.getNext(), stackDepth - 1);
	  ih = null;
	}
	// for all branches, the target of the branch is pushed on the branch stack.
	// conditional branches have a fall through case, selects don't, and
	// jsr/jsr_w return to the next instruction.
	branchTargets.push(branch.getTarget(), stackDepth);
      } else {
	// check for instructions that terminate the method.
	if(opcode == Constants.ATHROW || opcode == Constants.RET ||
	   (opcode >= Constants.IRETURN && opcode <= Constants.RETURN))
	  ih = null;
      }
      // normal case, go to the next instruction.
      if(ih != null)
	ih = ih.getNext();
      // if we have no more instructions, see if there are any deferred branches to explore.
      if(ih == null) {
	BranchTarget bt = branchTargets.pop();
	if (bt != null) {
	  ih = bt.target;
	  stackDepth = bt.stackDepth;
	}
      }
    }

    return maxStackDepth;
  
public com.sun.org.apache.bcel.internal.classfile.MethodgetMethod()
Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively, before calling this method (the same applies for max locals).

return
method object

    String signature       = getSignature();
    int    name_index      = cp.addUtf8(name);
    int    signature_index = cp.addUtf8(signature);

    /* Also updates positions of instructions, i.e., their indices
     */
    byte[] byte_code = null;

    if(il != null)
      byte_code = il.getByteCode();

    LineNumberTable    lnt = null;
    LocalVariableTable lvt = null;

    /* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.)
     */
    if((variable_vec.size() > 0) && !strip_attributes)
      addCodeAttribute(lvt = getLocalVariableTable(cp));

    if((line_number_vec.size() > 0) && !strip_attributes)
      addCodeAttribute(lnt = getLineNumberTable(cp));

    Attribute[] code_attrs = getCodeAttributes();

    /* Each attribute causes 6 additional header bytes
     */
    int                attrs_len  = 0;
    for(int i=0; i < code_attrs.length; i++)
      attrs_len += (code_attrs[i].getLength() + 6);

    CodeException[] c_exc   = getCodeExceptions();
    int             exc_len = c_exc.length * 8; // Every entry takes 8 bytes

    Code code = null;

    if((il != null) && !isAbstract()) {
      // Remove any stale code attribute
      Attribute[] attributes = getAttributes();
      for(int i=0; i < attributes.length; i++) {
	Attribute a = attributes[i];

	if(a instanceof Code)
	  removeAttribute(a);
      }

      code = new Code(cp.addUtf8("Code"),
		      8 + byte_code.length + // prologue byte code
		      2 + exc_len +          // exceptions
		      2 + attrs_len,         // attributes
		      max_stack, max_locals,
		      byte_code, c_exc,
		      code_attrs,
		      cp.getConstantPool());
      
      addAttribute(code);
    }

    ExceptionTable et = null;
    
    if(throws_vec.size() > 0)
      addAttribute(et = getExceptionTable(cp)); // Add `Exceptions' if there are "throws" clauses

    Method m = new Method(access_flags, name_index, signature_index,
			  getAttributes(), cp.getConstantPool());

    // Undo effects of adding attributes
    if(lvt != null)  removeCodeAttribute(lvt);
    if(lnt != null)  removeCodeAttribute(lnt);
    if(code != null) removeAttribute(code);
    if(et != null)   removeAttribute(et);

    return m;
  
public com.sun.org.apache.bcel.internal.generic.TypegetReturnType()

 return getType(); 
public java.lang.StringgetSignature()

 
    return Type.getMethodSignature(type, arg_types);
  
public voidremoveCodeAttribute(com.sun.org.apache.bcel.internal.classfile.Attribute a)
Remove a code attribute.

 code_attrs_vec.remove(a); 
public voidremoveCodeAttributes()
Remove all code attributes.

    code_attrs_vec.clear();
  
public voidremoveException(java.lang.String c)
Remove an exception.

    throws_vec.remove(c);  
  
public voidremoveExceptionHandler(com.sun.org.apache.bcel.internal.generic.CodeExceptionGen c)
Remove an exception handler.

    exception_vec.remove(c);  
  
public voidremoveExceptionHandlers()
Remove all line numbers.

    exception_vec.clear();
  
public voidremoveExceptions()
Remove all exceptions.

    throws_vec.clear();  
  
public voidremoveLineNumber(com.sun.org.apache.bcel.internal.generic.LineNumberGen l)
Remove a line number.

    line_number_vec.remove(l);  
  
public voidremoveLineNumbers()
Remove all line numbers.

    line_number_vec.clear();
  
public voidremoveLocalVariable(com.sun.org.apache.bcel.internal.generic.LocalVariableGen l)
Remove a local variable, its slot will not be reused, if you do not use addLocalVariable with an explicit index argument.

    variable_vec.remove(l);  
  
public voidremoveLocalVariables()
Remove all local variables.

    variable_vec.clear();
  
public voidremoveNOPs()
Remove all NOPs from the instruction list (if possible) and update every object refering to them, i.e., branch instructions, local variables and exception handlers.

    if(il != null) {
      InstructionHandle next;
      /* Check branch instructions.
       */
      for(InstructionHandle ih = il.getStart(); ih != null; ih = next) {
	next = ih.next;

	if((next != null) && (ih.getInstruction() instanceof NOP)) {
	  try {
	    il.delete(ih);
	  } catch(TargetLostException e) {
	    InstructionHandle[] targets = e.getTargets();
	    
	    for(int i=0; i < targets.length; i++) {
	      InstructionTargeter[] targeters = targets[i].getTargeters();
	      
	      for(int j=0; j < targeters.length; j++)
		targeters[j].updateTarget(targets[i], next);
	    }
	  }
	}
      }
    }
  
public voidremoveObserver(com.sun.org.apache.bcel.internal.generic.MethodObserver o)
Remove observer for this object.

    if(observers != null)
      observers.remove(o);
  
public voidsetArgumentName(int i, java.lang.String name)

 arg_names[i] = name; 
public voidsetArgumentNames(java.lang.String[] arg_names)

 this.arg_names = arg_names; 
public voidsetArgumentType(int i, com.sun.org.apache.bcel.internal.generic.Type type)

 arg_types[i] = type; 
public voidsetArgumentTypes(com.sun.org.apache.bcel.internal.generic.Type[] arg_types)

 this.arg_types = arg_types; 
public voidsetClassName(java.lang.String class_name)

 this.class_name = class_name; 
public voidsetInstructionList(com.sun.org.apache.bcel.internal.generic.InstructionList il)

 this.il = il; 
public voidsetMaxLocals(int m)
Set maximum number of local variables.

 max_locals = m; 
public voidsetMaxLocals()
Compute maximum number of local variables.

    if(il != null) {
      int max = isStatic()? 0 : 1;

      if(arg_types != null)
	for(int i=0; i < arg_types.length; i++)
	  max += arg_types[i].getSize();

      for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
	Instruction ins = ih.getInstruction();

	if((ins instanceof LocalVariableInstruction) ||
	   (ins instanceof RET) || (ins instanceof IINC))
	{
	  int index = ((IndexedInstruction)ins).getIndex() +
	    ((TypedInstruction)ins).getType(cp).getSize();

	  if(index > max)
	    max = index;
	}
      }

      max_locals = max;
    } else
      max_locals = 0;
  
public voidsetMaxStack(int m)
Set maximum stack size for this method.

 max_stack = m; 
public voidsetMaxStack()
Computes max. stack size by performing control flow analysis.

    if(il != null)
      max_stack = getMaxStack(cp, il, getExceptionHandlers());
    else
      max_stack = 0;
  
public voidsetReturnType(com.sun.org.apache.bcel.internal.generic.Type return_type)

 setType(return_type); 
private static final voidsort(com.sun.org.apache.bcel.internal.generic.LocalVariableGen[] vars, int l, int r)
Sort local variables by index

    int i = l, j = r;
    int m = vars[(l + r) / 2].getIndex();
    LocalVariableGen h;

    do {
      while(vars[i].getIndex() < m) i++;
      while(m < vars[j].getIndex()) j--;

      if(i <= j) {
        h=vars[i]; vars[i]=vars[j]; vars[j]=h; // Swap elements
        i++; j--;
      }
    } while(i <= j);

    if(l < j) sort(vars, l, j);
    if(i < r) sort(vars, i, r);
  
public voidstripAttributes(boolean flag)
Do not/Do produce attributes code attributesLineNumberTable and LocalVariableTable, like javac -O

 strip_attributes = flag; 
public final java.lang.StringtoString()
Return string representation close to declaration format, `public static void _main(String[]) throws IOException', e.g.

return
String representation of the method.

    String access    = Utility.accessToString(access_flags);
    String signature = Type.getMethodSignature(type, arg_types);

    signature = Utility.methodSignatureToString(signature, name, access,
						true, getLocalVariableTable(cp));

    StringBuffer buf = new StringBuffer(signature);

    if(throws_vec.size() > 0) {
      for(Iterator e = throws_vec.iterator(); e.hasNext(); )
	buf.append("\n\t\tthrows " + e.next());
    }
 
    return buf.toString();
  
public voidupdate()
Call notify() method on all observers. This method is not called automatically whenever the state has changed, but has to be called by the user after he has finished editing the object.

    if(observers != null)
      for(Iterator e = observers.iterator(); e.hasNext(); )
	((MethodObserver)e.next()).notify(this);