    View Javadoc
    1   package org.apache.bcel.generic;
    2
    3   /* ====================================================================
    4    * The Apache Software License, Version 1.1
    5    *
    6    * Copyright (c) 2001 The Apache Software Foundation.  All rights
    7    * reserved.
    8    *
    9    * Redistribution and use in source and binary forms, with or without
    10   * modification, are permitted provided that the following conditions
    11   * are met:
    12   *
    13   * 1. Redistributions of source code must retain the above copyright
    14   *    notice, this list of conditions and the following disclaimer.
    15   *
    16   * 2. Redistributions in binary form must reproduce the above copyright
    17   *    notice, this list of conditions and the following disclaimer in
    18   *    the documentation and/or other materials provided with the
    19   *    distribution.
    20   *
    21   * 3. The end-user documentation included with the redistribution,
    22   *    if any, must include the following acknowledgment:
    23   *       "This product includes software developed by the
    24   *        Apache Software Foundation (http://www.apache.org/)."
    25   *    Alternately, this acknowledgment may appear in the software itself,
    26   *    if and wherever such third-party acknowledgments normally appear.
    27   *
    28   * 4. The names "Apache" and "Apache Software Foundation" and
    29   *    "Apache BCEL" must not be used to endorse or promote products
    30   *    derived from this software without prior written permission. For
    31   *    written permission, please contact apache@apache.org.
    32   *
    33   * 5. Products derived from this software may not be called "Apache",
    34   *    "Apache BCEL", nor may "Apache" appear in their name, without
    35   *    prior written permission of the Apache Software Foundation.
    36   *
    37   * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
    38   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    39   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
    40   * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
    41   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    42   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    43   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
    44   * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    45   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
    46   * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
    47   * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    48   * SUCH DAMAGE.
    49   * ====================================================================
    50   *
    51   * This software consists of voluntary contributions made by many
    52   * individuals on behalf of the Apache Software Foundation.  For more
    53   * information on the Apache Software Foundation, please see
    54   * <http://www.apache.org/>;.
    55   */
    56
    57  import org.apache.bcel.Constants;
    58  import org.apache.bcel.classfile.*;
    59  import java.util.*;
    60
    61  /***
    62   * Template class for building up a method. This is done by defining exception
    63   * handlers, adding thrown exceptions, local variables and attributes, whereas
    64   * the `LocalVariableTable' and `LineNumberTable' attributes will be set
    65   * automatically for the code. Use stripAttributes() if you don't like this.
    66   *
    67   * While generating code it may be necessary to insert NOP operations. You can
    68   * use the `removeNOPs' method to get rid off them.
    69   * The resulting method object can be obtained via the `getMethod()' method.
    70   *
    71   * @version $Id: MethodGen.java,v 1.7 2003/02/13 11:18:23 enver Exp $
    72   * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
    73   * @author  <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A> [setMaxStack()]
    74   * @see     InstructionList
    75   * @see     Method
    76   */
    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    /***
    93     * Declare method. If the method is non-static the constructor
    94     * automatically declares a local variable `$this' in slot 0. The
    95     * actual code is contained in the `il' parameter, which may further
    96     * manipulated by the user. But he must take care not to remove any
    97     * instruction (handles) that are still referenced from this object.
    98     *
    99     * For example one may not add a local variable and later remove the
    100    * instructions it refers to without causing havoc. It is safe
    101    * however if you remove that local variable, too.
    102    *
    103    * @param access_flags access qualifiers
    104    * @param return_type  method type
    105    * @param arg_types argument types
    106    * @param arg_names argument names (if this is null, default names will be provided
    107    * for them)
    108    * @param method_name name of method
    109    * @param class_name class name containing this method (may be null, if you don't care)
    110    * @param il instruction list associated with this method, may be null only for
    111    * abstract or native methods
    112    * @param cp constant pool
    113    */
    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     boolean abstract_ = isAbstract() || isNative();
    127     InstructionHandle start = null;
    128     InstructionHandle end   = null;
    129
    130     if(!abstract_) {
    131       start = il.getStart();
    132       end   = il.getEnd();
    133
    134       /* Add local variables, namely the implicit `this' and the arguments
    135        */
    136       if(!isStatic() && (class_name != null)) { // Instance method -> `this' is local var 0
    137 	addLocalVariable("this", new ObjectType(class_name), start, end);
    138       }
    139     }
    140
    141     if(arg_types != null) {
    142       int size = arg_types.length;
    143
    144       for(int i=0; i < size; i++) {
    145 	if(Type.VOID == arg_types[i]) {
    146 	  throw new ClassGenException("'void' is an illegal argument type for a method");
    147 	}
    148       }
    149
    150       if(arg_names != null) { // Names for variables provided?
    151 	if(size != arg_names.length)
    152 	  throw new ClassGenException("Mismatch in argument array lengths: " +
    153 				      size + " vs. " + arg_names.length);
    154       } else { // Give them dummy names
    155 	arg_names = new String[size];
    156
    157 	for(int i=0; i < size; i++)
    158 	  arg_names[i] = "arg" + i;
    159
    160 	setArgumentNames(arg_names);
    161       }
    162
    163       if(!abstract_) {
    164 	for(int i=0; i < size; i++) {
    165 	  addLocalVariable(arg_names[i], arg_types[i], start, end);
    166 	}
    167       }
    168     }
    169   }
    170
    171   /***
    172    * Instantiate from existing method.
    173    *
    174    * @param m method
    175    * @param class_name class name containing this method
    176    * @param cp constant pool
    177    */
    178   public MethodGen(Method m, String class_name, ConstantPoolGen cp) {
    179     this(m.getAccessFlags(), Type.getReturnType(m.getSignature()),
    180 	 Type.getArgumentTypes(m.getSignature()), null /* may be overridden anyway */,
    181 	 m.getName(), class_name,
    182 	 ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0)?
    183 	 new InstructionList(m.getCode().getCode()) : null,
    184 	 cp);
    185
    186     Attribute[] attributes = m.getAttributes();
    187     for(int i=0; i < attributes.length; i++) {
    188       Attribute a = attributes[i];
    189
    190       if(a instanceof Code) {
    191 	Code c = (Code)a;
    192 	setMaxStack(c.getMaxStack());
    193 	setMaxLocals(c.getMaxLocals());
    194
    195 	CodeException[] ces = c.getExceptionTable();
    196
    197 	if(ces != null) {
    198 	  for(int j=0; j < ces.length; j++) {
    199             CodeException ce     = ces[j];
    200             int           type   = ce.getCatchType();
    201             ObjectType    c_type = null;
    202
    203 	    if(type > 0) {
    204 	      String cen = m.getConstantPool().getConstantString(type, Constants.CONSTANT_Class);
    205 	      c_type = new ObjectType(cen);
    206 	    }
    207
    208 	    int end_pc = ce.getEndPC();
    209 	    int length = m.getCode().getCode().length;
    210
    211 	    InstructionHandle end;
    212
    213 	    if(length == end_pc) { // May happen, because end_pc is exclusive
    214 	      end = il.getEnd();
    215 	    } else {
    216 	      end = il.findHandle(end_pc);
    217 	      end = end.getPrev(); // Make it inclusive
    218 	    }
    219
    220 	    addExceptionHandler(il.findHandle(ce.getStartPC()), end,
    221 				il.findHandle(ce.getHandlerPC()), c_type);
    222 	  }
    223 	}
    224
    225 	Attribute[] c_attributes = c.getAttributes();
    226 	for(int j=0; j < c_attributes.length; j++) {
    227 	  a = c_attributes[j];
    228
    229 	  if(a instanceof LineNumberTable) {
    230 	    LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable();
    231
    232 	    for(int k=0; k < ln.length; k++) {
    233 	      LineNumber l = ln[k];
    234 	      addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber());
    235 	    }
    236 	  } else if(a instanceof LocalVariableTable) {
    237 	    LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable();
    238
    239 	    removeLocalVariables();
    240
    241 	    for(int k=0; k < lv.length; k++) {
    242 	      LocalVariable     l     = lv[k];
    243 	      InstructionHandle start = il.findHandle(l.getStartPC());
    244 	      InstructionHandle end   = il.findHandle(l.getStartPC() + l.getLength());
    245
    246 	      // Repair malformed handles
    247 	      if(null == start) {
    248 		start = il.getStart();
    249 	      }
    250
    251 	      if(null == end) {
    252 		end = il.getEnd();
    253 	      }
    254
    255 	      addLocalVariable(l.getName(), Type.getType(l.getSignature()),
    256 			       l.getIndex(), start, end);
    257 	    }
    258 	  } else
    259 	    addCodeAttribute(a);
    260 	}
    261       } else if(a instanceof ExceptionTable) {
    262 	String[] names = ((ExceptionTable)a).getExceptionNames();
    263 	for(int j=0; j < names.length; j++)
    264 	  addException(names[j]);
    265       } else
    266 	addAttribute(a);
    267     }
    268   }
    269
    270   /***
    271    * Adds a local variable to this method.
    272    *
    273    * @param name variable name
    274    * @param type variable type
    275    * @param slot the index of the local variable, if type is long or double, the next available
    276    * index is slot+2
    277    * @param start from where the variable is valid
    278    * @param end until where the variable is valid
    279    * @return new local variable object
    280    * @see LocalVariable
    281    */
    282   public LocalVariableGen addLocalVariable(String name, Type type, int slot,
    283 					   InstructionHandle start,
    284 					   InstructionHandle end) {
    285     byte t = type.getType();
    286
    287     if(t != Constants.T_ADDRESS) {
    288       int  add = type.getSize();
    289
    290       if(slot + add > max_locals)
    291 	max_locals = slot + add;
    292
    293       LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
    294       int i;
    295
    296       if((i = variable_vec.indexOf(l)) >= 0) // Overwrite if necessary
    297 	variable_vec.set(i, l);
    298       else
    299 	variable_vec.add(l);
    300
    301       return l;
    302     } else {
    303       throw new IllegalArgumentException("Can not use " + type +
    304 					 " as type for local variable");
    305
    306     }
    307   }
    308
    309   /***
    310    * Adds a local variable to this method and assigns an index automatically.
    311    *
    312    * @param name variable name
    313    * @param type variable type
    314    * @param start from where the variable is valid, if this is null,
    315    * it is valid from the start
    316    * @param end until where the variable is valid, if this is null,
    317    * it is valid to the end
    318    * @return new local variable object
    319    * @see LocalVariable
    320    */
    321   public LocalVariableGen addLocalVariable(String name, Type type,
    322 					   InstructionHandle start,
    323 					   InstructionHandle end) {
    324     return addLocalVariable(name, type, max_locals, start, end);
    325   }
    326
    327   /***
    328    * Remove a local variable, its slot will not be reused, if you do not use addLocalVariable
    329    * with an explicit index argument.
    330    */
    331   public void removeLocalVariable(LocalVariableGen l) {
    332     variable_vec.remove(l);
    333   }
    334
    335   /***
    336    * Remove all local variables.
    337    */
    338   public void removeLocalVariables() {
    339     variable_vec.clear();
    340   }
    341
    342   /***
    343    * Sort local variables by index
    344    */
    345   private static final void sort(LocalVariableGen[] vars, int l, int r) {
    346     int i = l, j = r;
    347     int m = vars[(l + r) / 2].getIndex();
    348     LocalVariableGen h;
    349
    350     do {
    351       while(vars[i].getIndex() < m) i++;
    352       while(m < vars[j].getIndex()) j--;
    353
    354       if(i <= j) {
    355         h=vars[i]; vars[i]=vars[j]; vars[j]=h; // Swap elements
    356         i++; j--;
    357       }
    358     } while(i <= j);
    359
    360     if(l < j) sort(vars, l, j);
    361     if(i < r) sort(vars, i, r);
    362   }
    363
    364   /*
    365    * If the range of the variable has not been set yet, it will be set to be valid from
    366    * the start to the end of the instruction list.
    367    *
    368    * @return array of declared local variables sorted by index
    369    */
    370   public LocalVariableGen[] getLocalVariables() {
    371     int                size = variable_vec.size();
    372     LocalVariableGen[] lg   = new LocalVariableGen[size];
    373     variable_vec.toArray(lg);
    374
    375     for(int i=0; i < size; i++) {
    376       if(lg[i].getStart() == null)
    377 	lg[i].setStart(il.getStart());
    378
    379       if(lg[i].getEnd() == null)
    380 	lg[i].setEnd(il.getEnd());
    381     }
    382
    383     if(size > 1)
    384       sort(lg, 0, size - 1);
    385
    386     return lg;
    387   }
    388
    389   /***
    390    * @return `LocalVariableTable' attribute of all the local variables of this method.
    391    */
    392   public LocalVariableTable getLocalVariableTable(ConstantPoolGen cp) {
    393     LocalVariableGen[] lg   = getLocalVariables();
    394     int                size = lg.length;
    395     LocalVariable[]    lv   = new LocalVariable[size];
    396
    397     for(int i=0; i < size; i++)
    398       lv[i] = lg[i].getLocalVariable(cp);
    399
    400     return new LocalVariableTable(cp.addUtf8("LocalVariableTable"),
    401 				  2 + lv.length * 10, lv, cp.getConstantPool());
    402   }
    403
    404   /***
    405    * Give an instruction a line number corresponding to the source code line.
    406    *
    407    * @param ih instruction to tag
    408    * @return new line number object
    409    * @see LineNumber
    410    */
    411   public LineNumberGen addLineNumber(InstructionHandle ih, int src_line) {
    412     LineNumberGen l = new LineNumberGen(ih, src_line);
    413     line_number_vec.add(l);
    414     return l;
    415   }
    416
    417   /***
    418    * Remove a line number.
    419    */
    420   public void removeLineNumber(LineNumberGen l) {
    421     line_number_vec.remove(l);
    422   }
    423
    424   /***
    425    * Remove all line numbers.
    426    */
    427   public void removeLineNumbers() {
    428     line_number_vec.clear();
    429   }
    430
    431   /*
    432    * @return array of line numbers
    433    */
    434   public LineNumberGen[] getLineNumbers() {
    435     LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()];
    436     line_number_vec.toArray(lg);
    437     return lg;
    438   }
    439
    440   /***
    441    * @return `LineNumberTable' attribute of all the local variables of this method.
    442    */
    443   public LineNumberTable getLineNumberTable(ConstantPoolGen cp) {
    444     int          size = line_number_vec.size();
    445     LineNumber[] ln   = new LineNumber[size];
    446
    447     try {
    448       for(int i=0; i < size; i++)
    449 	ln[i] = ((LineNumberGen)line_number_vec.get(i)).getLineNumber();
    450     } catch(ArrayIndexOutOfBoundsException e) {} // Never occurs
    451
    452     return new LineNumberTable(cp.addUtf8("LineNumberTable"),
    453 			       2 + ln.length * 4, ln, cp.getConstantPool());
    454   }
    455
    456   /***
    457    * Add an exception handler, i.e., specify region where a handler is active and an
    458    * instruction where the actual handling is done.
    459    *
    460    * @param start_pc Start of region (inclusive)
    461    * @param end_pc End of region (inclusive)
    462    * @param handler_pc Where handling is done
    463    * @param catch_type class type of handled exception or null if any
    464    * exception is handled
    465    * @return new exception handler object
    466    */
    467   public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
    468 					      InstructionHandle end_pc,
    469 					      InstructionHandle handler_pc,
    470 					      ObjectType catch_type) {
    471     if((start_pc == null) || (end_pc == null) || (handler_pc == null))
    472       throw new ClassGenException("Exception handler target is null instruction");
    473
    474     CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc,
    475 					      handler_pc, catch_type);
    476     exception_vec.add(c);
    477     return c;
    478   }
    479
    480   /***
    481    * Remove an exception handler.
    482    */
    483   public void removeExceptionHandler(CodeExceptionGen c) {
    484     exception_vec.remove(c);
    485   }
    486
    487   /***
    488    * Remove all line numbers.
    489    */
    490   public void removeExceptionHandlers() {
    491     exception_vec.clear();
    492   }
    493
    494   /*
    495    * @return array of declared exception handlers
    496    */
    497   public CodeExceptionGen[] getExceptionHandlers() {
    498     CodeExceptionGen[] cg   = new CodeExceptionGen[exception_vec.size()];
    499     exception_vec.toArray(cg);
    500     return cg;
    501   }
    502
    503   /***
    504    * @return code exceptions for `Code' attribute
    505    */
    506   private CodeException[] getCodeExceptions() {
    507     int             size  = exception_vec.size();
    508     CodeException[] c_exc = new CodeException[size];
    509
    510     try {
    511       for(int i=0; i < size; i++) {
    512 	CodeExceptionGen c = (CodeExceptionGen)exception_vec.get(i);
    513 	c_exc[i] = c.getCodeException(cp);
    514       }
    515     } catch(ArrayIndexOutOfBoundsException e) {}
    516
    517     return c_exc;
    518   }
    519
    520   /***
    521    * Add an exception possibly thrown by this method.
    522    *
    523    * @param class_name (fully qualified) name of exception
    524    */
    525   public void addException(String class_name) {
    526     throws_vec.add(class_name);
    527   }
    528
    529   /***
    530    * Remove an exception.
    531    */
    532   public void removeException(String c) {
    533     throws_vec.remove(c);
    534   }
    535
    536   /***
    537    * Remove all exceptions.
    538    */
    539   public void removeExceptions() {
    540     throws_vec.clear();
    541   }
    542
    543   /*
    544    * @return array of thrown exceptions
    545    */
    546   public String[] getExceptions() {
    547     String[] e = new String[throws_vec.size()];
    548     throws_vec.toArray(e);
    549     return e;
    550   }
    551
    552   /***
    553    * @return `Exceptions' attribute of all the exceptions thrown by this method.
    554    */
    555   private ExceptionTable getExceptionTable(ConstantPoolGen cp) {
    556     int   size = throws_vec.size();
    557     int[] ex   = new int[size];
    558
    559     try {
    560       for(int i=0; i < size; i++)
    561 	ex[i] = cp.addClass((String)throws_vec.get(i));
    562     } catch(ArrayIndexOutOfBoundsException e) {}
    563
    564     return new ExceptionTable(cp.addUtf8("Exceptions"),
    565 			      2 + 2 * size, ex, cp.getConstantPool());
    566   }
    567
    568   /***
    569    * Add an attribute to the code. Currently, the JVM knows about the
    570    * LineNumberTable, LocalVariableTable and StackMap attributes,
    571    * where the former two will be generated automatically and the
    572    * latter is used for the MIDP only. Other attributes will be
    573    * ignored by the JVM but do no harm.
    574    *
    575    * @param a attribute to be added
    576    */
    577   public void addCodeAttribute(Attribute a) { code_attrs_vec.add(a); }
    578
    579   /***
    580    * Remove a code attribute.
    581    */
    582   public void removeCodeAttribute(Attribute a) { code_attrs_vec.remove(a); }
    583
    584   /***
    585    * Remove all code attributes.
    586    */
    587   public void removeCodeAttributes() {
    588     code_attrs_vec.clear();
    589   }
    590
    591   /***
    592    * @return all attributes of this method.
    593    */
    594   public Attribute[] getCodeAttributes() {
    595     Attribute[] attributes = new Attribute[code_attrs_vec.size()];
    596     code_attrs_vec.toArray(attributes);
    597     return attributes;
    598   }
    599
    600   /***
    601    * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively,
    602    * before calling this method (the same applies for max locals).
    603    *
    604    * @return method object
    605    */
    606   public Method getMethod() {
    607     String signature       = getSignature();
    608     int    name_index      = cp.addUtf8(name);
    609     int    signature_index = cp.addUtf8(signature);
    610
    611     /* Also updates positions of instructions, i.e., their indices
    612      */
    613     byte[] byte_code = null;
    614
    615     if(il != null)
    616       byte_code = il.getByteCode();
    617
    618     LineNumberTable    lnt = null;
    619     LocalVariableTable lvt = null;
    620
    621     /* Create LocalVariableTable and LineNumberTable attributes (for debuggers, e.g.)
    622      */
    623     if((variable_vec.size() > 0) && !strip_attributes)
    624       addCodeAttribute(lvt = getLocalVariableTable(cp));
    625
    626     if((line_number_vec.size() > 0) && !strip_attributes)
    627       addCodeAttribute(lnt = getLineNumberTable(cp));
    628
    629     Attribute[] code_attrs = getCodeAttributes();
    630
    631     /* Each attribute causes 6 additional header bytes
    632      */
    633     int                attrs_len  = 0;
    634     for(int i=0; i < code_attrs.length; i++)
    635       attrs_len += (code_attrs[i].getLength() + 6);
    636
    637     CodeException[] c_exc   = getCodeExceptions();
    638     int             exc_len = c_exc.length * 8; // Every entry takes 8 bytes
    639
    640     Code code = null;
    641
    642     if((il != null) && !isAbstract()) {
    643       // Remove any stale code attribute
    644       Attribute[] attributes = getAttributes();
    645       for(int i=0; i < attributes.length; i++) {
    646 	Attribute a = attributes[i];
    647
    648 	if(a instanceof Code)
    649 	  removeAttribute(a);
    650       }
    651
    652       code = new Code(cp.addUtf8("Code"),
    653 		      8 + byte_code.length + // prologue byte code
    654 		      2 + exc_len +          // exceptions
    655 		      2 + attrs_len,         // attributes
    656 		      max_stack, max_locals,
    657 		      byte_code, c_exc,
    658 		      code_attrs,
    659 		      cp.getConstantPool());
    660
    661       addAttribute(code);
    662     }
    663
    664     ExceptionTable et = null;
    665
    666     if(throws_vec.size() > 0)
    667       addAttribute(et = getExceptionTable(cp)); // Add `Exceptions' if there are "throws" clauses
    668
    669     Method m = new Method(access_flags, name_index, signature_index,
    670 			  getAttributes(), cp.getConstantPool());
    671
    672     // Undo effects of adding attributes
    673     if(lvt != null)  removeCodeAttribute(lvt);
    674     if(lnt != null)  removeCodeAttribute(lnt);
    675     if(code != null) removeAttribute(code);
    676     if(et != null)   removeAttribute(et);
    677
    678     return m;
    679   }
    680
    681   /***
    682    * Remove all NOPs from the instruction list (if possible) and update every
    683    * object refering to them, i.e., branch instructions, local variables and
    684    * exception handlers.
    685    */
    686   public void removeNOPs() {
    687     if(il != null) {
    688       InstructionHandle next;
    689       /* Check branch instructions.
    690        */
    691       for(InstructionHandle ih = il.getStart(); ih != null; ih = next) {
    692 	next = ih.next;
    693
    694 	if((next != null) && (ih.getInstruction() instanceof NOP)) {
    695 	  try {
    696 	    il.delete(ih);
    697 	  } catch(TargetLostException e) {
    698 	    InstructionHandle[] targets = e.getTargets();
    699
    700 	    for(int i=0; i < targets.length; i++) {
    701 	      InstructionTargeter[] targeters = targets[i].getTargeters();
    702
    703 	      for(int j=0; j < targeters.length; j++)
    704 		targeters[j].updateTarget(targets[i], next);
    705 	    }
    706 	  }
    707 	}
    708       }
    709     }
    710   }
    711
    712   /***
    713    * Set maximum number of local variables.
    714    */
    715   public void   setMaxLocals(int m)  { max_locals = m; }
    716   public int    getMaxLocals()       { return max_locals; }
    717
    718   /***
    719    * Set maximum stack size for this method.
    720    */
    721   public void   setMaxStack(int m)  { max_stack = m; }
    722   public int    getMaxStack()       { return max_stack; }
    723
    724   /*** @return class that contains this method
    725    */
    726   public String getClassName()                     { return class_name; }
    727   public void   setClassName(String class_name)    { this.class_name = class_name; }
    728
    729   public void   setReturnType(Type return_type)    { setType(return_type); }
    730   public Type   getReturnType()                    { return getType(); }
    731
    732   public void   setArgumentTypes(Type[] arg_types)  { this.arg_types = arg_types; }
    733   public Type[] getArgumentTypes()                  { return (Type[])arg_types.clone(); }
    734   public void   setArgumentType(int i, Type type)       { arg_types[i] = type; }
    735   public Type   getArgumentType(int i)                  { return arg_types[i]; }
    736
    737   public void     setArgumentNames(String[] arg_names) { this.arg_names = arg_names; }
    738   public String[] getArgumentNames()                   { return (String[])arg_names.clone(); }
    739   public void     setArgumentName(int i, String name)     { arg_names[i] = name; }
    740   public String   getArgumentName(int i)                  { return arg_names[i]; }
    741
    742   public InstructionList getInstructionList()                    { return il; }
    743   public void            setInstructionList(InstructionList il)  { this.il = il; }
    744
    745   public String getSignature() {
    746     return Type.getMethodSignature(type, arg_types);
    747   }
    748
    749   /***
    750    * Computes max. stack size by performing control flow analysis.
    751    */
    752   public void setMaxStack() {
    753     if(il != null)
    754       max_stack = getMaxStack(cp, il, getExceptionHandlers());
    755     else
    756       max_stack = 0;
    757   }
    758
    759   /***
    760    * Compute maximum number of local variables.
    761    */
    762   public void setMaxLocals() {
    763     if(il != null) {
    764       int max = isStatic()? 0 : 1;
    765
    766       if(arg_types != null)
    767 	for(int i=0; i < arg_types.length; i++)
    768 	  max += arg_types[i].getSize();
    769
    770       for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
    771 	Instruction ins = ih.getInstruction();
    772
    773 	if((ins instanceof LocalVariableInstruction) ||
    774 	   (ins instanceof RET) || (ins instanceof IINC))
    775 	{
    776 	  int index = ((IndexedInstruction)ins).getIndex() +
    777 	    ((TypedInstruction)ins).getType(cp).getSize();
    778
    779 	  if(index > max)
    780 	    max = index;
    781 	}
    782       }
    783
    784       max_locals = max;
    785     } else
    786       max_locals = 0;
    787   }
    788
    789   /*** Do not/Do produce attributes code attributesLineNumberTable and
    790    * LocalVariableTable, like javac -O
    791    */
    792   public void stripAttributes(boolean flag) { strip_attributes = flag; }
    793
    794   static final class BranchTarget {
    795     InstructionHandle target;
    796     int               stackDepth;
    797
    798     BranchTarget(InstructionHandle target, int stackDepth) {
    799       this.target = target;
    800       this.stackDepth = stackDepth;
    801     }
    802   }
    803
    804   static final class BranchStack {
    805     Stack     branchTargets  = new Stack();
    806     Hashtable visitedTargets = new Hashtable();
    807
    808     public void push(InstructionHandle target, int stackDepth) {
    809       if(visited(target))
    810 	return;
    811
    812       branchTargets.push(visit(target, stackDepth));
    813     }
    814
    815     public BranchTarget pop() {
    816       if(!branchTargets.empty()) {
    817 	BranchTarget bt = (BranchTarget) branchTargets.pop();
    818 	return bt;
    819       }
    820
    821       return null;
    822     }
    823
    824     private final BranchTarget visit(InstructionHandle target, int stackDepth) {
    825       BranchTarget bt = new BranchTarget(target, stackDepth);
    826       visitedTargets.put(target, bt);
    827
    828       return bt;
    829     }
    830
    831     private final boolean visited(InstructionHandle target) {
    832       return (visitedTargets.get(target) != null);
    833     }
    834   }
    835
    836   /***
    837    * Computes stack usage of an instruction list by performing control flow analysis.
    838    *
    839    * @return maximum stack depth used by method
    840    */
    841   public static int getMaxStack(ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et) {
    842     BranchStack branchTargets = new BranchStack();
    843
    844     /* Initially, populate the branch stack with the exception
    845      * handlers, because these aren't (necessarily) branched to
    846      * explicitly. in each case, the stack will have depth 1,
    847      * containing the exception object.
    848      */
    849     for (int i = 0; i < et.length; i++) {
    850       InstructionHandle handler_pc = et[i].getHandlerPC();
    851       if (handler_pc != null)
    852 	branchTargets.push(handler_pc, 1);
    853     }
    854
    855     int               stackDepth = 0, maxStackDepth = 0;
    856     InstructionHandle ih         = il.getStart();
    857
    858     while(ih != null) {
    859       Instruction instruction = ih.getInstruction();
    860       short opcode = instruction.getOpcode();
    861       int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
    862
    863       stackDepth += delta;
    864       if(stackDepth > maxStackDepth)
    865 	maxStackDepth = stackDepth;
    866
    867       // choose the next instruction based on whether current is a branch.
    868       if(instruction instanceof BranchInstruction) {
    869 	BranchInstruction branch = (BranchInstruction) instruction;
    870 	if(instruction instanceof Select) {
    871 	  // explore all of the select's targets. the default target is handled below.
    872 	  Select select = (Select) branch;
    873 	  InstructionHandle[] targets = select.getTargets();
    874 	  for (int i = 0; i < targets.length; i++)
    875 	    branchTargets.push(targets[i], stackDepth);
    876 	  // nothing to fall through to.
    877 	  ih = null;
    878 	} else if(!(branch instanceof IfInstruction)) {
    879 	  // if an instruction that comes back to following PC,
    880 	  // push next instruction, with stack depth reduced by 1.
    881 	  if(opcode == Constants.JSR || opcode == Constants.JSR_W)
    882 	    branchTargets.push(ih.getNext(), stackDepth - 1);
    883 	  ih = null;
    884 	}
    885 	// for all branches, the target of the branch is pushed on the branch stack.
    886 	// conditional branches have a fall through case, selects don't, and
    887 	// jsr/jsr_w return to the next instruction.
    888 	branchTargets.push(branch.getTarget(), stackDepth);
    889       } else {
    890 	// check for instructions that terminate the method.
    891 	if(opcode == Constants.ATHROW || opcode == Constants.RET ||
    892 	   (opcode >= Constants.IRETURN && opcode <= Constants.RETURN))
    893 	  ih = null;
    894       }
    895       // normal case, go to the next instruction.
    896       if(ih != null)
    897 	ih = ih.getNext();
    898       // if we have no more instructions, see if there are any deferred branches to explore.
    899       if(ih == null) {
    900 	BranchTarget bt = branchTargets.pop();
    901 	if (bt != null) {
    902 	  ih = bt.target;
    903 	  stackDepth = bt.stackDepth;
    904 	}
    905       }
    906     }
    907
    908     return maxStackDepth;
    909   }
    910
    911   private ArrayList observers;
    912
    913   /*** Add observer for this object.
    914    */
    915   public void addObserver(MethodObserver o) {
    916     if(observers == null)
    917       observers = new ArrayList();
    918
    919     observers.add(o);
    920   }
    921
    922   /*** Remove observer for this object.
    923    */
    924   public void removeObserver(MethodObserver o) {
    925     if(observers != null)
    926       observers.remove(o);
    927   }
    928
    929   /*** Call notify() method on all observers. This method is not called
    930    * automatically whenever the state has changed, but has to be
    931    * called by the user after he has finished editing the object.
    932    */
    933   public void update() {
    934     if(observers != null)
    935       for(Iterator e = observers.iterator(); e.hasNext(); )
    936 	((MethodObserver)e.next()).notify(this);
    937   }
    938
    939   /***
    940    * Return string representation close to declaration format,
    941    * `public static void main(String[]) throws IOException', e.g.
    942    *
    943    * @return String representation of the method.
    944    */
    945   public final String toString() {
    946     String access    = Utility.accessToString(access_flags);
    947     String signature = Type.getMethodSignature(type, arg_types);
    948
    949     signature = Utility.methodSignatureToString(signature, name, access,
    950 						true, getLocalVariableTable(cp));
    951
    952     StringBuffer buf = new StringBuffer(signature);
    953
    954     if(throws_vec.size() > 0) {
    955       for(Iterator e = throws_vec.iterator(); e.hasNext(); )
    956 	buf.append("\n\t\tthrows " + e.next());
    957     }
    958
    959     return buf.toString();
    960   }
    961
    962   /*** @return deep copy of this method
    963    */
    964   public MethodGen copy(String class_name, ConstantPoolGen cp) {
    965     Method    m  = ((MethodGen)clone()).getMethod();
    966     MethodGen mg = new MethodGen(m, class_name, this.cp);
    967
    968     if(this.cp != cp) {
    969       mg.setConstantPool(cp);
    970       mg.getInstructionList().replaceConstantPool(this.cp, cp);
    971     }
    972
    973     return mg;
    974   }
    975 }

This page was automatically generated by Maven