jaxp/src/java.xml/share/classes/com/sun/org/apache/bcel/internal/generic/MethodGen.java
changeset 46174 5611d2529b49
parent 44797 8b3b3b911b8a
equal deleted inserted replaced
46173:5546b5710844 46174:5611d2529b49
     1 /*
     1 /*
     2  * reserved comment block
     2  * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT REMOVE OR ALTER!
       
     4  */
     3  */
     5 /*
     4 /*
     6  * Licensed to the Apache Software Foundation (ASF) under one or more
     5  * Licensed to the Apache Software Foundation (ASF) under one or more
     7  * contributor license agreements.  See the NOTICE file distributed with
     6  * contributor license agreements.  See the NOTICE file distributed with
     8  * this work for additional information regarding copyright ownership.
     7  * this work for additional information regarding copyright ownership.
    16  * distributed under the License is distributed on an "AS IS" BASIS,
    15  * distributed under the License is distributed on an "AS IS" BASIS,
    17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    18  * See the License for the specific language governing permissions and
    17  * See the License for the specific language governing permissions and
    19  * limitations under the License.
    18  * limitations under the License.
    20  */
    19  */
    21 
       
    22 package com.sun.org.apache.bcel.internal.generic;
    20 package com.sun.org.apache.bcel.internal.generic;
    23 
    21 
    24 
    22 import com.sun.org.apache.bcel.internal.Const;
    25 import com.sun.org.apache.bcel.internal.Constants;
    23 import com.sun.org.apache.bcel.internal.classfile.AnnotationEntry;
    26 import com.sun.org.apache.bcel.internal.classfile.*;
    24 import com.sun.org.apache.bcel.internal.classfile.Annotations;
    27 import java.util.*;
    25 import com.sun.org.apache.bcel.internal.classfile.Attribute;
       
    26 import com.sun.org.apache.bcel.internal.classfile.Code;
       
    27 import com.sun.org.apache.bcel.internal.classfile.CodeException;
       
    28 import com.sun.org.apache.bcel.internal.classfile.ExceptionTable;
       
    29 import com.sun.org.apache.bcel.internal.classfile.LineNumber;
       
    30 import com.sun.org.apache.bcel.internal.classfile.LineNumberTable;
       
    31 import com.sun.org.apache.bcel.internal.classfile.LocalVariable;
       
    32 import com.sun.org.apache.bcel.internal.classfile.LocalVariableTable;
       
    33 import com.sun.org.apache.bcel.internal.classfile.LocalVariableTypeTable;
       
    34 import com.sun.org.apache.bcel.internal.classfile.Method;
       
    35 import com.sun.org.apache.bcel.internal.classfile.ParameterAnnotationEntry;
       
    36 import com.sun.org.apache.bcel.internal.classfile.ParameterAnnotations;
       
    37 import com.sun.org.apache.bcel.internal.classfile.RuntimeVisibleParameterAnnotations;
       
    38 import com.sun.org.apache.bcel.internal.classfile.Utility;
       
    39 import com.sun.org.apache.bcel.internal.util.BCELComparator;
       
    40 import java.util.ArrayList;
       
    41 import java.util.Arrays;
       
    42 import java.util.Comparator;
       
    43 import java.util.HashMap;
       
    44 import java.util.List;
       
    45 import java.util.Map;
       
    46 import java.util.Stack;
    28 
    47 
    29 /**
    48 /**
    30  * Template class for building up a method. This is done by defining exception
    49  * Template class for building up a method. This is done by defining exception
    31  * handlers, adding thrown exceptions, local variables and attributes, whereas
    50  * handlers, adding thrown exceptions, local variables and attributes, whereas
    32  * the `LocalVariableTable' and `LineNumberTable' attributes will be set
    51  * the `LocalVariableTable' and `LineNumberTable' attributes will be set
    33  * automatically for the code. Use stripAttributes() if you don't like this.
    52  * automatically for the code. Use stripAttributes() if you don't like this.
    34  *
    53  *
    35  * While generating code it may be necessary to insert NOP operations. You can
    54  * While generating code it may be necessary to insert NOP operations. You can
    36  * use the `removeNOPs' method to get rid off them.
    55  * use the `removeNOPs' method to get rid off them. The resulting method object
    37  * The resulting method object can be obtained via the `getMethod()' method.
    56  * can be obtained via the `getMethod()' method.
    38  *
    57  *
    39  * @author  <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
    58  * @version $Id: MethodGen.java 1749603 2016-06-21 20:50:19Z ggregory $
    40  * @author  <A HREF="http://www.vmeng.com/beard">Patrick C. Beard</A> [setMaxStack()]
    59  * @see InstructionList
    41  * @see     InstructionList
    60  * @see Method
    42  * @see     Method
       
    43  */
    61  */
    44 public class MethodGen extends FieldGenOrMethodGen {
    62 public class MethodGen extends FieldGenOrMethodGen {
    45   private String          class_name;
    63 
    46   private Type[]          arg_types;
    64     private String class_name;
    47   private String[]        arg_names;
    65     private Type[] arg_types;
    48   private int             max_locals;
    66     private String[] arg_names;
    49   private int             max_stack;
    67     private int max_locals;
    50   private InstructionList il;
    68     private int max_stack;
    51   private boolean         strip_attributes;
    69     private InstructionList il;
    52 
    70     private boolean strip_attributes;
    53   private ArrayList       variable_vec    = new ArrayList();
    71     private final List<LocalVariableGen> variable_vec = new ArrayList<>();
    54   private ArrayList       type_vec        = new ArrayList();
    72     private final List<LocalVariableGen> type_vec = new ArrayList<>();
    55   private ArrayList       line_number_vec = new ArrayList();
    73     private final List<LineNumberGen> line_number_vec = new ArrayList<>();
    56   private ArrayList       exception_vec   = new ArrayList();
    74     private final List<CodeExceptionGen> exception_vec = new ArrayList<>();
    57   private ArrayList       throws_vec      = new ArrayList();
    75     private final List<String> throws_vec = new ArrayList<>();
    58   private ArrayList       code_attrs_vec  = new ArrayList();
    76     private final List<Attribute> code_attrs_vec = new ArrayList<>();
    59 
    77 
    60   /**
    78     private List<AnnotationEntryGen>[] param_annotations; // Array of lists containing AnnotationGen objects
    61    * Declare method. If the method is non-static the constructor
    79     private boolean hasParameterAnnotations = false;
    62    * automatically declares a local variable `$this' in slot 0. The
    80     private boolean haveUnpackedParameterAnnotations = false;
    63    * actual code is contained in the `il' parameter, which may further
    81 
    64    * manipulated by the user. But he must take care not to remove any
    82     private static BCELComparator bcelComparator = new BCELComparator() {
    65    * instruction (handles) that are still referenced from this object.
    83 
    66    *
    84         @Override
    67    * For example one may not add a local variable and later remove the
    85         public boolean equals(final Object o1, final Object o2) {
    68    * instructions it refers to without causing havoc. It is safe
    86             final MethodGen THIS = (MethodGen) o1;
    69    * however if you remove that local variable, too.
    87             final MethodGen THAT = (MethodGen) o2;
    70    *
    88             return THIS.getName().equals(THAT.getName())
    71    * @param access_flags access qualifiers
    89                     && THIS.getSignature().equals(THAT.getSignature());
    72    * @param return_type  method type
    90         }
    73    * @param arg_types argument types
    91 
    74    * @param arg_names argument names (if this is null, default names will be provided
    92         @Override
    75    * for them)
    93         public int hashCode(final Object o) {
    76    * @param method_name name of method
    94             final MethodGen THIS = (MethodGen) o;
    77    * @param class_name class name containing this method (may be null, if you don't care)
    95             return THIS.getSignature().hashCode() ^ THIS.getName().hashCode();
    78    * @param il instruction list associated with this method, may be null only for
    96         }
    79    * abstract or native methods
    97     };
    80    * @param cp constant pool
    98 
    81    */
    99     /**
    82   public MethodGen(int access_flags, Type return_type, Type[] arg_types,
   100      * Declare method. If the method is non-static the constructor automatically
    83                    String[] arg_names, String method_name, String class_name,
   101      * declares a local variable `$this' in slot 0. The actual code is contained
    84                    InstructionList il, ConstantPoolGen cp) {
   102      * in the `il' parameter, which may further manipulated by the user. But he
    85     setAccessFlags(access_flags);
   103      * must take care not to remove any instruction (handles) that are still
    86     setType(return_type);
   104      * referenced from this object.
    87     setArgumentTypes(arg_types);
   105      *
    88     setArgumentNames(arg_names);
   106      * For example one may not add a local variable and later remove the
    89     setName(method_name);
   107      * instructions it refers to without causing havoc. It is safe however if
    90     setClassName(class_name);
   108      * you remove that local variable, too.
    91     setInstructionList(il);
   109      *
    92     setConstantPool(cp);
   110      * @param access_flags access qualifiers
    93 
   111      * @param return_type method type
    94     boolean abstract_ = isAbstract() || isNative();
   112      * @param arg_types argument types
    95     InstructionHandle start = null;
   113      * @param arg_names argument names (if this is null, default names will be
    96     InstructionHandle end   = null;
   114      * provided for them)
    97 
   115      * @param method_name name of method
    98     if(!abstract_) {
   116      * @param class_name class name containing this method (may be null, if you
    99       start = il.getStart();
   117      * don't care)
   100       end   = il.getEnd();
   118      * @param il instruction list associated with this method, may be null only
   101 
   119      * for abstract or native methods
   102       /* Add local variables, namely the implicit `this' and the arguments
   120      * @param cp constant pool
   103        */
   121      */
   104       if(!isStatic() && (class_name != null)) { // Instance method -> `this' is local var 0
   122     public MethodGen(final int access_flags, final Type return_type, final Type[] arg_types, String[] arg_names,
   105         addLocalVariable("this", new ObjectType(class_name), start, end);
   123             final String method_name, final String class_name, final InstructionList il, final ConstantPoolGen cp) {
   106       }
   124         super(access_flags);
   107     }
   125         setType(return_type);
   108 
   126         setArgumentTypes(arg_types);
   109     if(arg_types != null) {
       
   110       int size = arg_types.length;
       
   111 
       
   112       for(int i=0; i < size; i++) {
       
   113         if(Type.VOID == arg_types[i]) {
       
   114           throw new ClassGenException("'void' is an illegal argument type for a method");
       
   115         }
       
   116       }
       
   117 
       
   118       if(arg_names != null) { // Names for variables provided?
       
   119         if(size != arg_names.length)
       
   120           throw new ClassGenException("Mismatch in argument array lengths: " +
       
   121                                       size + " vs. " + arg_names.length);
       
   122       } else { // Give them dummy names
       
   123         arg_names = new String[size];
       
   124 
       
   125         for(int i=0; i < size; i++)
       
   126           arg_names[i] = "arg" + i;
       
   127 
       
   128         setArgumentNames(arg_names);
   127         setArgumentNames(arg_names);
   129       }
   128         setName(method_name);
   130 
   129         setClassName(class_name);
   131       if(!abstract_) {
   130         setInstructionList(il);
   132         for(int i=0; i < size; i++) {
   131         setConstantPool(cp);
   133           addLocalVariable(arg_names[i], arg_types[i], start, end);
   132         final boolean abstract_ = isAbstract() || isNative();
   134         }
   133         InstructionHandle start = null;
   135       }
   134         InstructionHandle end = null;
   136     }
   135         if (!abstract_) {
   137   }
   136             start = il.getStart();
   138 
   137             end = il.getEnd();
   139   /**
   138             /* Add local variables, namely the implicit `this' and the arguments
   140    * Instantiate from existing method.
   139              */
   141    *
   140             if (!isStatic() && (class_name != null)) { // Instance method -> `this' is local var 0
   142    * @param m method
   141                 addLocalVariable("this", ObjectType.getInstance(class_name), start, end);
   143    * @param class_name class name containing this method
   142             }
   144    * @param cp constant pool
   143         }
   145    */
   144         if (arg_types != null) {
   146   public MethodGen(Method m, String class_name, ConstantPoolGen cp) {
   145             final int size = arg_types.length;
   147     this(m.getAccessFlags(), Type.getReturnType(m.getSignature()),
   146             for (final Type arg_type : arg_types) {
   148          Type.getArgumentTypes(m.getSignature()), null /* may be overridden anyway */,
   147                 if (Type.VOID == arg_type) {
   149          m.getName(), class_name,
   148                     throw new ClassGenException("'void' is an illegal argument type for a method");
   150          ((m.getAccessFlags() & (Constants.ACC_ABSTRACT | Constants.ACC_NATIVE)) == 0)?
   149                 }
   151          new InstructionList(m.getCode().getCode()) : null,
   150             }
   152          cp);
   151             if (arg_names != null) { // Names for variables provided?
   153 
   152                 if (size != arg_names.length) {
   154     Attribute[] attributes = m.getAttributes();
   153                     throw new ClassGenException("Mismatch in argument array lengths: " + size
   155     for(int i=0; i < attributes.length; i++) {
   154                             + " vs. " + arg_names.length);
   156       Attribute a = attributes[i];
   155                 }
   157 
   156             } else { // Give them dummy names
   158       if(a instanceof Code) {
   157                 arg_names = new String[size];
   159         Code c = (Code)a;
   158                 for (int i = 0; i < size; i++) {
   160         setMaxStack(c.getMaxStack());
   159                     arg_names[i] = "arg" + i;
   161         setMaxLocals(c.getMaxLocals());
   160                 }
   162 
   161                 setArgumentNames(arg_names);
   163         CodeException[] ces = c.getExceptionTable();
   162             }
   164 
   163             if (!abstract_) {
   165         if(ces != null) {
   164                 for (int i = 0; i < size; i++) {
   166           for(int j=0; j < ces.length; j++) {
   165                     addLocalVariable(arg_names[i], arg_types[i], start, end);
   167             CodeException ce     = ces[j];
   166                 }
   168             int           type   = ce.getCatchType();
   167             }
   169             ObjectType    c_type = null;
   168         }
   170 
   169     }
   171             if(type > 0) {
   170 
   172               String cen = m.getConstantPool().getConstantString(type, Constants.CONSTANT_Class);
   171     /**
   173               c_type = new ObjectType(cen);
   172      * Instantiate from existing method.
   174             }
   173      *
   175 
   174      * @param m method
   176             int end_pc = ce.getEndPC();
   175      * @param class_name class name containing this method
   177             int length = m.getCode().getCode().length;
   176      * @param cp constant pool
   178 
   177      */
   179             InstructionHandle end;
   178     public MethodGen(final Method m, final String class_name, final ConstantPoolGen cp) {
   180 
   179         this(m.getAccessFlags(), Type.getReturnType(m.getSignature()), Type.getArgumentTypes(m
   181             if(length == end_pc) { // May happen, because end_pc is exclusive
   180                 .getSignature()), null /* may be overridden anyway */, m.getName(), class_name,
   182               end = il.getEnd();
   181                 ((m.getAccessFlags() & (Const.ACC_ABSTRACT | Const.ACC_NATIVE)) == 0)
       
   182                 ? new InstructionList(m.getCode().getCode())
       
   183                 : null, cp);
       
   184         final Attribute[] attributes = m.getAttributes();
       
   185         for (final Attribute attribute : attributes) {
       
   186             Attribute a = attribute;
       
   187             if (a instanceof Code) {
       
   188                 final Code c = (Code) a;
       
   189                 setMaxStack(c.getMaxStack());
       
   190                 setMaxLocals(c.getMaxLocals());
       
   191                 final CodeException[] ces = c.getExceptionTable();
       
   192                 if (ces != null) {
       
   193                     for (final CodeException ce : ces) {
       
   194                         final int type = ce.getCatchType();
       
   195                         ObjectType c_type = null;
       
   196                         if (type > 0) {
       
   197                             final String cen = m.getConstantPool().getConstantString(type,
       
   198                                     Const.CONSTANT_Class);
       
   199                             c_type = ObjectType.getInstance(cen);
       
   200                         }
       
   201                         final int end_pc = ce.getEndPC();
       
   202                         final int length = m.getCode().getCode().length;
       
   203                         InstructionHandle end;
       
   204                         if (length == end_pc) { // May happen, because end_pc is exclusive
       
   205                             end = il.getEnd();
       
   206                         } else {
       
   207                             end = il.findHandle(end_pc);
       
   208                             end = end.getPrev(); // Make it inclusive
       
   209                         }
       
   210                         addExceptionHandler(il.findHandle(ce.getStartPC()), end, il.findHandle(ce
       
   211                                 .getHandlerPC()), c_type);
       
   212                     }
       
   213                 }
       
   214                 final Attribute[] c_attributes = c.getAttributes();
       
   215                 for (final Attribute c_attribute : c_attributes) {
       
   216                     a = c_attribute;
       
   217                     if (a instanceof LineNumberTable) {
       
   218                         final LineNumber[] ln = ((LineNumberTable) a).getLineNumberTable();
       
   219                         for (final LineNumber l : ln) {
       
   220                             final InstructionHandle ih = il.findHandle(l.getStartPC());
       
   221                             if (ih != null) {
       
   222                                 addLineNumber(ih, l.getLineNumber());
       
   223                             }
       
   224                         }
       
   225                     } else if (a instanceof LocalVariableTable) {
       
   226                         final LocalVariable[] lv = ((LocalVariableTable) a).getLocalVariableTable();
       
   227                         removeLocalVariables();
       
   228                         repairHandles(lv, false);
       
   229                     } else if (a instanceof LocalVariableTypeTable) {
       
   230                         LocalVariable[] lv = ((LocalVariableTypeTable) a).getLocalVariableTypeTable();
       
   231                         removeLocalVariableTypes();
       
   232                         repairHandles(lv, true);
       
   233                     } else {
       
   234                         addCodeAttribute(a);
       
   235                     }
       
   236                 }
       
   237             } else if (a instanceof ExceptionTable) {
       
   238                 final String[] names = ((ExceptionTable) a).getExceptionNames();
       
   239                 for (final String name2 : names) {
       
   240                     addException(name2);
       
   241                 }
       
   242             } else if (a instanceof Annotations) {
       
   243                 final Annotations runtimeAnnotations = (Annotations) a;
       
   244                 final AnnotationEntry[] aes = runtimeAnnotations.getAnnotationEntries();
       
   245                 for (final AnnotationEntry element : aes) {
       
   246                     addAnnotationEntry(new AnnotationEntryGen(element, cp, false));
       
   247                 }
   183             } else {
   248             } else {
   184               end = il.findHandle(end_pc);
   249                 addAttribute(a);
   185               end = end.getPrev(); // Make it inclusive
   250             }
   186             }
   251         }
   187 
   252     }
   188             addExceptionHandler(il.findHandle(ce.getStartPC()), end,
   253 
   189                                 il.findHandle(ce.getHandlerPC()), c_type);
   254     private void repairHandles(final LocalVariable[] lv, boolean isLVT) {
   190           }
   255         for (int k = 0; k < lv.length; k++) {
   191         }
   256             LocalVariable l = lv[k];
   192 
   257             InstructionHandle start = il.findHandle(l.getStartPC());
   193         Attribute[] c_attributes = c.getAttributes();
   258             InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
   194         for(int j=0; j < c_attributes.length; j++) {
   259             // Repair malformed handles
   195           a = c_attributes[j];
   260             if (null == start) {
   196 
       
   197           if(a instanceof LineNumberTable) {
       
   198             LineNumber[] ln = ((LineNumberTable)a).getLineNumberTable();
       
   199 
       
   200             for(int k=0; k < ln.length; k++) {
       
   201               LineNumber l = ln[k];
       
   202               addLineNumber(il.findHandle(l.getStartPC()), l.getLineNumber());
       
   203             }
       
   204           } else if(a instanceof LocalVariableTable) {
       
   205             LocalVariable[] lv = ((LocalVariableTable)a).getLocalVariableTable();
       
   206 
       
   207             removeLocalVariables();
       
   208 
       
   209             for(int k=0; k < lv.length; k++) {
       
   210               LocalVariable     l     = lv[k];
       
   211               InstructionHandle start = il.findHandle(l.getStartPC());
       
   212               InstructionHandle end   = il.findHandle(l.getStartPC() + l.getLength());
       
   213 
       
   214               // Repair malformed handles
       
   215               if(null == start) {
       
   216                 start = il.getStart();
   261                 start = il.getStart();
   217               }
   262             }
   218 
   263             if (null == end) {
   219               if(null == end) {
       
   220                 end = il.getEnd();
   264                 end = il.getEnd();
   221               }
   265             }
   222 
   266             if (isLVT) {
   223               addLocalVariable(l.getName(), Type.getType(l.getSignature()),
   267                 addLocalVariableType(l.getName(), Type.getType(l.getSignature()),
   224                                l.getIndex(), start, end);
   268                         l.getIndex(), start, end);
   225             }
   269             } else {
   226           } else if (a instanceof LocalVariableTypeTable) {
   270                 addLocalVariable(l.getName(), Type.getType(l.getSignature()),
   227              LocalVariable[] lv = ((LocalVariableTypeTable) a).getLocalVariableTypeTable();
   271                         l.getIndex(), start, end);
   228              removeLocalVariableTypes();
   272             }
   229              for (int k = 0; k < lv.length; k++) {
   273         }
   230                  LocalVariable l = lv[k];
   274     }
   231                  InstructionHandle start = il.findHandle(l.getStartPC());
   275 
   232                  InstructionHandle end = il.findHandle(l.getStartPC() + l.getLength());
   276     /**
   233                  // Repair malformed handles
   277      * Adds a local variable to this method.
   234                  if (null == start) {
   278      *
   235                      start = il.getStart();
   279      * @param name variable name
   236                  }
   280      * @param type variable type
   237                  if (null == end) {
   281      * @param slot the index of the local variable, if type is long or double,
   238                      end = il.getEnd();
   282      * the next available index is slot+2
   239                  }
   283      * @param start from where the variable is valid
   240                  addLocalVariableType(l.getName(), Type.getType(l.getSignature()), l
   284      * @param end until where the variable is valid
   241                          .getIndex(), start, end);
   285      * @return new local variable object
   242               }
   286      * @see LocalVariable
   243           } else
   287      */
   244             addCodeAttribute(a);
   288     public LocalVariableGen addLocalVariable(final String name, final Type type, final int slot,
   245         }
   289             final InstructionHandle start, final InstructionHandle end) {
   246       } else if(a instanceof ExceptionTable) {
   290 
   247         String[] names = ((ExceptionTable)a).getExceptionNames();
   291         final byte t = type.getType();
   248         for(int j=0; j < names.length; j++)
   292         if (t != Const.T_ADDRESS) {
   249           addException(names[j]);
   293             final int add = type.getSize();
   250       } else
   294             if (slot + add > max_locals) {
   251         addAttribute(a);
   295                 max_locals = slot + add;
   252     }
   296             }
   253   }
   297             final LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
   254 
   298             int i;
   255   /**
   299             if ((i = variable_vec.indexOf(l)) >= 0) {
   256    * Adds a local variable to this method.
   300                 variable_vec.set(i, l);
   257    *
   301             } else {
   258    * @param name variable name
   302                 variable_vec.add(l);
   259    * @param type variable type
   303             }
   260    * @param slot the index of the local variable, if type is long or double, the next available
   304             return l;
   261    * index is slot+2
   305         }
   262    * @param start from where the variable is valid
   306         throw new IllegalArgumentException("Can not use " + type
   263    * @param end until where the variable is valid
   307                 + " as type for local variable");
   264    * @return new local variable object
   308     }
   265    * @see LocalVariable
   309 
   266    */
   310     /**
   267   public LocalVariableGen addLocalVariable(String name, Type type, int slot,
   311      * Adds a local variable to this method and assigns an index automatically.
   268                                            InstructionHandle start,
   312      *
   269                                            InstructionHandle end) {
   313      * @param name variable name
   270     byte t = type.getType();
   314      * @param type variable type
   271 
   315      * @param start from where the variable is valid, if this is null, it is
   272     if(t != Constants.T_ADDRESS) {
   316      * valid from the start
   273       int  add = type.getSize();
   317      * @param end until where the variable is valid, if this is null, it is
   274 
   318      * valid to the end
   275       if(slot + add > max_locals)
   319      * @return new local variable object
   276         max_locals = slot + add;
   320      * @see LocalVariable
   277 
   321      */
   278       LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
   322     public LocalVariableGen addLocalVariable(final String name, final Type type,
   279       int i;
   323             final InstructionHandle start, final InstructionHandle end) {
   280 
   324         return addLocalVariable(name, type, max_locals, start, end);
   281       if((i = variable_vec.indexOf(l)) >= 0) // Overwrite if necessary
   325     }
   282         variable_vec.set(i, l);
   326 
   283       else
   327     /**
   284         variable_vec.add(l);
   328      * Remove a local variable, its slot will not be reused, if you do not use
   285 
   329      * addLocalVariable with an explicit index argument.
   286       return l;
   330      */
   287     } else {
   331     public void removeLocalVariable(final LocalVariableGen l) {
   288       throw new IllegalArgumentException("Can not use " + type +
   332         variable_vec.remove(l);
   289                                          " as type for local variable");
   333     }
   290 
   334 
   291     }
   335     /**
   292   }
   336      * Remove all local variables.
   293 
   337      */
   294   /**
   338     public void removeLocalVariables() {
   295    * Adds a local variable to this method and assigns an index automatically.
   339         variable_vec.clear();
   296    *
   340     }
   297    * @param name variable name
   341 
   298    * @param type variable type
   342     /*
   299    * @param start from where the variable is valid, if this is null,
   343      * If the range of the variable has not been set yet, it will be set to be valid from
   300    * it is valid from the start
   344      * the start to the end of the instruction list.
   301    * @param end until where the variable is valid, if this is null,
   345      *
   302    * it is valid to the end
   346      * @return array of declared local variables sorted by index
   303    * @return new local variable object
   347      */
   304    * @see LocalVariable
   348     public LocalVariableGen[] getLocalVariables() {
   305    */
   349         return getLocalVariableOrTypes(false);
   306   public LocalVariableGen addLocalVariable(String name, Type type,
   350     }
   307                                            InstructionHandle start,
   351 
   308                                            InstructionHandle end) {
   352     /*
   309     return addLocalVariable(name, type, max_locals, start, end);
   353      * If the range of the variable has not been set yet, it will be set to be
   310   }
   354      * valid from the start to the end of the instruction list.
   311 
   355      *
   312   /**
   356      * @return array of declared local variable types sorted by index
   313    * Remove a local variable, its slot will not be reused, if you do not use addLocalVariable
   357      */
   314    * with an explicit index argument.
   358     private LocalVariableGen[] getLocalVariableTypes() {
   315    */
   359         return getLocalVariableOrTypes(true);
   316   public void removeLocalVariable(LocalVariableGen l) {
   360     }
   317     variable_vec.remove(l);
   361 
   318   }
   362     /*
   319 
   363      * If the range of the variable or type has not been set yet, it will be set
   320   /**
   364      * to be valid from the start to the end of the instruction list.
   321    * Remove all local variables.
   365      *
   322    */
   366      * @return array of declared local variables or types sorted by index
   323   public void removeLocalVariables() {
   367      */
   324     variable_vec.clear();
   368     private LocalVariableGen[] getLocalVariableOrTypes(boolean isLVT) {
   325   }
   369         int size = (isLVT) ? type_vec.size() : variable_vec.size();
   326 
   370         LocalVariableGen[] lg = new LocalVariableGen[size];
   327   /**
   371         if (isLVT) {
   328    * Sort local variables by index
   372             type_vec.toArray(lg);
   329    */
   373         } else {
   330   private static final void sort(LocalVariableGen[] vars, int l, int r) {
   374             variable_vec.toArray(lg);
   331     int i = l, j = r;
   375         }
   332     int m = vars[(l + r) / 2].getIndex();
   376 
   333     LocalVariableGen h;
   377         for (int i = 0; i < size; i++) {
   334 
   378             if (lg[i].getStart() == null) {
   335     do {
   379                 lg[i].setStart(il.getStart());
   336       while(vars[i].getIndex() < m) i++;
   380             }
   337       while(m < vars[j].getIndex()) j--;
   381 
   338 
   382             if (lg[i].getEnd() == null) {
   339       if(i <= j) {
   383                 lg[i].setEnd(il.getEnd());
   340         h=vars[i]; vars[i]=vars[j]; vars[j]=h; // Swap elements
   384             }
   341         i++; j--;
   385         }
   342       }
   386 
   343     } while(i <= j);
   387         if (size > 1) {
   344 
   388             Arrays.sort(lg, new Comparator<LocalVariableGen>() {
   345     if(l < j) sort(vars, l, j);
   389                 @Override
   346     if(i < r) sort(vars, i, r);
   390                 public int compare(final LocalVariableGen o1, final LocalVariableGen o2) {
   347   }
   391                     return o1.getIndex() - o2.getIndex();
   348 
   392                 }
   349   /*
   393             });
   350    * If the range of the variable has not been set yet, it will be set to be valid from
   394         }
   351    * the start to the end of the instruction list.
   395 
   352    *
   396         return lg;
   353    * @return array of declared local variables sorted by index
   397     }
   354    */
   398 
   355   public LocalVariableGen[] getLocalVariables() {
   399     /**
   356     int                size = variable_vec.size();
   400      * @return `LocalVariableTable' attribute of all the local variables of this
   357     LocalVariableGen[] lg   = new LocalVariableGen[size];
   401      * method.
   358     variable_vec.toArray(lg);
   402      */
   359 
   403     public LocalVariableTable getLocalVariableTable(final ConstantPoolGen cp) {
   360     for(int i=0; i < size; i++) {
   404         final LocalVariableGen[] lg = getLocalVariables();
   361       if(lg[i].getStart() == null)
   405         final int size = lg.length;
   362         lg[i].setStart(il.getStart());
   406         final LocalVariable[] lv = new LocalVariable[size];
   363 
   407         for (int i = 0; i < size; i++) {
   364       if(lg[i].getEnd() == null)
   408             lv[i] = lg[i].getLocalVariable(cp);
   365         lg[i].setEnd(il.getEnd());
   409         }
   366     }
   410         return new LocalVariableTable(cp.addUtf8("LocalVariableTable"), 2 + lv.length * 10, lv, cp
   367 
   411                 .getConstantPool());
   368     if(size > 1)
   412     }
   369       sort(lg, 0, size - 1);
   413 
   370 
   414     /**
   371     return lg;
   415      * @return `LocalVariableTypeTable' attribute of all the local variable
   372   }
   416      * types of this method.
   373 
   417      */
   374   /*
   418     public LocalVariableTypeTable getLocalVariableTypeTable(ConstantPoolGen cp) {
   375    * If the range of the variable has not been set yet, it will be set to be
   419         LocalVariableGen[] lg = getLocalVariableTypes();
   376    * val id from the start to the end of the instruction list.
   420         int size = lg.length;
   377    *
   421         LocalVariable[] lv = new LocalVariable[size];
   378    * @return array of declared local variable types sorted by index
   422 
   379    */
   423         for (int i = 0; i < size; i++) {
   380   private LocalVariableGen[] getLocalVariableTypes() {
   424             lv[i] = lg[i].getLocalVariable(cp);
   381     int                size = type_vec.size();
   425         }
   382     LocalVariableGen[] lg   = new LocalVariableGen[size];
   426 
   383     type_vec.toArray(lg);
   427         return new LocalVariableTypeTable(cp.addUtf8("LocalVariableTypeTable"),
   384 
   428                 2 + lv.length * 10, lv, cp.getConstantPool());
   385     for(int i=0; i < size; i++) {
   429     }
   386       if(lg[i].getStart() == null)
   430 
   387         lg[i].setStart(il.getStart());
   431     /**
   388 
   432      * Adds a local variable type to this method.
   389       if(lg[i].getEnd() == null)
   433      *
   390         lg[i].setEnd(il.getEnd());
   434      * @param name variable name
   391     }
   435      * @param type variable type
   392 
   436      * @param slot the index of the local variable, if type is long or double,
   393     if(size > 1)
   437      * the next available index is slot+2
   394       sort(lg, 0, size - 1);
   438      * @param start from where the variable is valid
   395 
   439      * @param end until where the variable is valid
   396     return lg;
   440      * @return new local variable object
   397   }
   441      * @see LocalVariable
   398 
   442      */
   399   /**
   443     private LocalVariableGen addLocalVariableType(String name, Type type, int slot,
   400    * @return `LocalVariableTable' attribute of all the local variables of this method.
   444             InstructionHandle start,
   401    */
   445             InstructionHandle end) {
   402   public LocalVariableTable getLocalVariableTable(ConstantPoolGen cp) {
   446         byte t = type.getType();
   403     LocalVariableGen[] lg   = getLocalVariables();
   447 
   404     int                size = lg.length;
   448         if (t != Const.T_ADDRESS) {
   405     LocalVariable[]    lv   = new LocalVariable[size];
   449             int add = type.getSize();
   406 
   450 
   407     for(int i=0; i < size; i++)
   451             if (slot + add > max_locals) {
   408       lv[i] = lg[i].getLocalVariable(cp);
   452                 max_locals = slot + add;
   409 
   453             }
   410     return new LocalVariableTable(cp.addUtf8("LocalVariableTable"),
   454 
   411                                   2 + lv.length * 10, lv, cp.getConstantPool());
   455             LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
   412   }
   456             int i;
   413 
   457 
   414   /**
   458             if ((i = type_vec.indexOf(l)) >= 0) // Overwrite if necessary
   415    * @return `LocalVariableTypeTable' attribute of all the local variable
   459             {
   416    * types of this method.
   460                 type_vec.set(i, l);
   417    */
   461             } else {
   418   public LocalVariableTypeTable getLocalVariableTypeTable(ConstantPoolGen cp) {
   462                 type_vec.add(l);
   419     LocalVariableGen[] lg   = getLocalVariableTypes();
   463             }
   420     int                size = lg.length;
   464 
   421     LocalVariable[]    lv   = new LocalVariable[size];
   465             return l;
   422 
   466         } else {
   423     for(int i=0; i < size; i++)
   467             throw new IllegalArgumentException("Can not use " + type
   424       lv[i] = lg[i].getLocalVariable(cp);
   468                     + " as type for local variable");
   425 
   469         }
   426     return new LocalVariableTypeTable(cp.addUtf8("LocalVariableTypeTable"),
   470     }
   427                                   2 + lv.length * 10, lv, cp.getConstantPool());
   471 
   428   }
   472     /**
   429 
   473      * Remove all local variable types.
   430   /**
   474      */
   431    * Adds a local variable type to this method.
   475     private void removeLocalVariableTypes() {
   432    *
   476         type_vec.clear();
   433    * @param name variable name
   477     }
   434    * @param type variable type
   478 
   435    * @param slot the index of the local variable, if type is long or double, the next available
   479     /**
   436    * index is slot+2
   480      * Give an instruction a line number corresponding to the source code line.
   437    * @param start from where the variable is valid
   481      *
   438    * @param end until where the variable is valid
   482      * @param ih instruction to tag
   439    * @return new local variable object
   483      * @return new line number object
   440    * @see LocalVariable
   484      * @see LineNumber
   441    */
   485      */
   442   private LocalVariableGen addLocalVariableType(String name, Type type, int slot,
   486     public LineNumberGen addLineNumber(final InstructionHandle ih, final int src_line) {
   443                                            InstructionHandle start,
   487         final LineNumberGen l = new LineNumberGen(ih, src_line);
   444                                            InstructionHandle end) {
   488         line_number_vec.add(l);
   445     byte t = type.getType();
   489         return l;
   446 
   490     }
   447     if(t != Constants.T_ADDRESS) {
   491 
   448       int  add = type.getSize();
   492     /**
   449 
   493      * Remove a line number.
   450       if(slot + add > max_locals)
   494      */
   451         max_locals = slot + add;
   495     public void removeLineNumber(final LineNumberGen l) {
   452 
   496         line_number_vec.remove(l);
   453       LocalVariableGen l = new LocalVariableGen(slot, name, type, start, end);
   497     }
   454       int i;
   498 
   455 
   499     /**
   456       if((i = type_vec.indexOf(l)) >= 0) // Overwrite if necessary
   500      * Remove all line numbers.
   457         type_vec.set(i, l);
   501      */
   458       else
   502     public void removeLineNumbers() {
   459         type_vec.add(l);
   503         line_number_vec.clear();
   460 
   504     }
   461       return l;
   505 
   462     } else {
   506     /*
   463       throw new IllegalArgumentException("Can not use " + type +
   507      * @return array of line numbers
   464                                          " as type for local variable");
   508      */
   465 
   509     public LineNumberGen[] getLineNumbers() {
   466     }
   510         final LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()];
   467   }
   511         line_number_vec.toArray(lg);
   468 
   512         return lg;
   469   /**
   513     }
   470    * Remove all local variable types.
   514 
   471    */
   515     /**
   472   private void removeLocalVariableTypes() {
   516      * @return `LineNumberTable' attribute of all the local variables of this
   473     type_vec.clear();
   517      * method.
   474   }
   518      */
   475 
   519     public LineNumberTable getLineNumberTable(final ConstantPoolGen cp) {
   476   /**
   520         final int size = line_number_vec.size();
   477    * Give an instruction a line number corresponding to the source code line.
   521         final LineNumber[] ln = new LineNumber[size];
   478    *
   522         for (int i = 0; i < size; i++) {
   479    * @param ih instruction to tag
   523             ln[i] = line_number_vec.get(i).getLineNumber();
   480    * @return new line number object
   524         }
   481    * @see LineNumber
   525         return new LineNumberTable(cp.addUtf8("LineNumberTable"), 2 + ln.length * 4, ln, cp
   482    */
   526                 .getConstantPool());
   483   public LineNumberGen addLineNumber(InstructionHandle ih, int src_line) {
   527     }
   484     LineNumberGen l = new LineNumberGen(ih, src_line);
   528 
   485     line_number_vec.add(l);
   529     /**
   486     return l;
   530      * Add an exception handler, i.e., specify region where a handler is active
   487   }
   531      * and an instruction where the actual handling is done.
   488 
   532      *
   489   /**
   533      * @param start_pc Start of region (inclusive)
   490    * Remove a line number.
   534      * @param end_pc End of region (inclusive)
   491    */
   535      * @param handler_pc Where handling is done
   492   public void removeLineNumber(LineNumberGen l) {
   536      * @param catch_type class type of handled exception or null if any
   493     line_number_vec.remove(l);
   537      * exception is handled
   494   }
   538      * @return new exception handler object
   495 
   539      */
   496   /**
   540     public CodeExceptionGen addExceptionHandler(final InstructionHandle start_pc,
   497    * Remove all line numbers.
   541             final InstructionHandle end_pc, final InstructionHandle handler_pc, final ObjectType catch_type) {
   498    */
   542         if ((start_pc == null) || (end_pc == null) || (handler_pc == null)) {
   499   public void removeLineNumbers() {
   543             throw new ClassGenException("Exception handler target is null instruction");
   500     line_number_vec.clear();
   544         }
   501   }
   545         final CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc, handler_pc, catch_type);
   502 
   546         exception_vec.add(c);
   503   /*
   547         return c;
   504    * @return array of line numbers
   548     }
   505    */
   549 
   506   public LineNumberGen[] getLineNumbers() {
   550     /**
   507     LineNumberGen[] lg = new LineNumberGen[line_number_vec.size()];
   551      * Remove an exception handler.
   508     line_number_vec.toArray(lg);
   552      */
   509     return lg;
   553     public void removeExceptionHandler(final CodeExceptionGen c) {
   510   }
   554         exception_vec.remove(c);
   511 
   555     }
   512   /**
   556 
   513    * @return `LineNumberTable' attribute of all the local variables of this method.
   557     /**
   514    */
   558      * Remove all line numbers.
   515   public LineNumberTable getLineNumberTable(ConstantPoolGen cp) {
   559      */
   516     int          size = line_number_vec.size();
   560     public void removeExceptionHandlers() {
   517     LineNumber[] ln   = new LineNumber[size];
   561         exception_vec.clear();
   518 
   562     }
   519     try {
   563 
   520       for(int i=0; i < size; i++)
   564     /*
   521         ln[i] = ((LineNumberGen)line_number_vec.get(i)).getLineNumber();
   565      * @return array of declared exception handlers
   522     } catch(ArrayIndexOutOfBoundsException e) {} // Never occurs
   566      */
   523 
   567     public CodeExceptionGen[] getExceptionHandlers() {
   524     return new LineNumberTable(cp.addUtf8("LineNumberTable"),
   568         final CodeExceptionGen[] cg = new CodeExceptionGen[exception_vec.size()];
   525                                2 + ln.length * 4, ln, cp.getConstantPool());
   569         exception_vec.toArray(cg);
   526   }
   570         return cg;
   527 
   571     }
   528   /**
   572 
   529    * Add an exception handler, i.e., specify region where a handler is active and an
   573     /**
   530    * instruction where the actual handling is done.
   574      * @return code exceptions for `Code' attribute
   531    *
   575      */
   532    * @param start_pc Start of region (inclusive)
   576     private CodeException[] getCodeExceptions() {
   533    * @param end_pc End of region (inclusive)
   577         final int size = exception_vec.size();
   534    * @param handler_pc Where handling is done
   578         final CodeException[] c_exc = new CodeException[size];
   535    * @param catch_type class type of handled exception or null if any
   579         for (int i = 0; i < size; i++) {
   536    * exception is handled
   580             final CodeExceptionGen c = exception_vec.get(i);
   537    * @return new exception handler object
   581             c_exc[i] = c.getCodeException(super.getConstantPool());
   538    */
   582         }
   539   public CodeExceptionGen addExceptionHandler(InstructionHandle start_pc,
   583         return c_exc;
   540                                               InstructionHandle end_pc,
   584     }
   541                                               InstructionHandle handler_pc,
   585 
   542                                               ObjectType catch_type) {
   586     /**
   543     if((start_pc == null) || (end_pc == null) || (handler_pc == null))
   587      * Add an exception possibly thrown by this method.
   544       throw new ClassGenException("Exception handler target is null instruction");
   588      *
   545 
   589      * @param class_name (fully qualified) name of exception
   546     CodeExceptionGen c = new CodeExceptionGen(start_pc, end_pc,
   590      */
   547                                               handler_pc, catch_type);
   591     public void addException(final String class_name) {
   548     exception_vec.add(c);
   592         throws_vec.add(class_name);
   549     return c;
   593     }
   550   }
   594 
   551 
   595     /**
   552   /**
   596      * Remove an exception.
   553    * Remove an exception handler.
   597      */
   554    */
   598     public void removeException(final String c) {
   555   public void removeExceptionHandler(CodeExceptionGen c) {
   599         throws_vec.remove(c);
   556     exception_vec.remove(c);
   600     }
   557   }
   601 
   558 
   602     /**
   559   /**
   603      * Remove all exceptions.
   560    * Remove all line numbers.
   604      */
   561    */
   605     public void removeExceptions() {
   562   public void removeExceptionHandlers() {
   606         throws_vec.clear();
   563     exception_vec.clear();
   607     }
   564   }
   608 
   565 
   609     /*
   566   /*
   610      * @return array of thrown exceptions
   567    * @return array of declared exception handlers
   611      */
   568    */
   612     public String[] getExceptions() {
   569   public CodeExceptionGen[] getExceptionHandlers() {
   613         final String[] e = new String[throws_vec.size()];
   570     CodeExceptionGen[] cg   = new CodeExceptionGen[exception_vec.size()];
   614         throws_vec.toArray(e);
   571     exception_vec.toArray(cg);
   615         return e;
   572     return cg;
   616     }
   573   }
   617 
   574 
   618     /**
   575   /**
   619      * @return `Exceptions' attribute of all the exceptions thrown by this
   576    * @return code exceptions for `Code' attribute
   620      * method.
   577    */
   621      */
   578   private CodeException[] getCodeExceptions() {
   622     private ExceptionTable getExceptionTable(final ConstantPoolGen cp) {
   579     int             size  = exception_vec.size();
   623         final int size = throws_vec.size();
   580     CodeException[] c_exc = new CodeException[size];
   624         final int[] ex = new int[size];
   581 
   625         for (int i = 0; i < size; i++) {
   582     try {
   626             ex[i] = cp.addClass(throws_vec.get(i));
   583       for(int i=0; i < size; i++) {
   627         }
   584         CodeExceptionGen c = (CodeExceptionGen)exception_vec.get(i);
   628         return new ExceptionTable(cp.addUtf8("Exceptions"), 2 + 2 * size, ex, cp.getConstantPool());
   585         c_exc[i] = c.getCodeException(cp);
   629     }
   586       }
   630 
   587     } catch(ArrayIndexOutOfBoundsException e) {}
   631     /**
   588 
   632      * Add an attribute to the code. Currently, the JVM knows about the
   589     return c_exc;
   633      * LineNumberTable, LocalVariableTable and StackMap attributes, where the
   590   }
   634      * former two will be generated automatically and the latter is used for the
   591 
   635      * MIDP only. Other attributes will be ignored by the JVM but do no harm.
   592   /**
   636      *
   593    * Add an exception possibly thrown by this method.
   637      * @param a attribute to be added
   594    *
   638      */
   595    * @param class_name (fully qualified) name of exception
   639     public void addCodeAttribute(final Attribute a) {
   596    */
   640         code_attrs_vec.add(a);
   597   public void addException(String class_name) {
   641     }
   598     throws_vec.add(class_name);
   642 
   599   }
   643     /**
   600 
   644      * Remove a code attribute.
   601   /**
   645      */
   602    * Remove an exception.
   646     public void removeCodeAttribute(final Attribute a) {
   603    */
   647         code_attrs_vec.remove(a);
   604   public void removeException(String c) {
   648     }
   605     throws_vec.remove(c);
   649 
   606   }
   650     /**
   607 
   651      * Remove all code attributes.
   608   /**
   652      */
   609    * Remove all exceptions.
   653     public void removeCodeAttributes() {
   610    */
   654         code_attrs_vec.clear();
   611   public void removeExceptions() {
   655     }
   612     throws_vec.clear();
   656 
   613   }
   657     /**
   614 
   658      * @return all attributes of this method.
   615   /*
   659      */
   616    * @return array of thrown exceptions
   660     public Attribute[] getCodeAttributes() {
   617    */
   661         final Attribute[] attributes = new Attribute[code_attrs_vec.size()];
   618   public String[] getExceptions() {
   662         code_attrs_vec.toArray(attributes);
   619     String[] e = new String[throws_vec.size()];
   663         return attributes;
   620     throws_vec.toArray(e);
   664     }
   621     return e;
   665 
   622   }
   666     /**
   623 
   667      * @since 6.0
   624   /**
   668      */
   625    * @return `Exceptions' attribute of all the exceptions thrown by this method.
   669     public void addAnnotationsAsAttribute(final ConstantPoolGen cp) {
   626    */
   670         final Attribute[] attrs = AnnotationEntryGen.getAnnotationAttributes(cp, super.getAnnotationEntries());
   627   private ExceptionTable getExceptionTable(ConstantPoolGen cp) {
   671         for (final Attribute attr : attrs) {
   628     int   size = throws_vec.size();
   672             addAttribute(attr);
   629     int[] ex   = new int[size];
   673         }
   630 
   674     }
   631     try {
   675 
   632       for(int i=0; i < size; i++)
   676     /**
   633         ex[i] = cp.addClass((String)throws_vec.get(i));
   677      * @since 6.0
   634     } catch(ArrayIndexOutOfBoundsException e) {}
   678      */
   635 
   679     public void addParameterAnnotationsAsAttribute(final ConstantPoolGen cp) {
   636     return new ExceptionTable(cp.addUtf8("Exceptions"),
   680         if (!hasParameterAnnotations) {
   637                               2 + 2 * size, ex, cp.getConstantPool());
   681             return;
   638   }
   682         }
   639 
   683         final Attribute[] attrs = AnnotationEntryGen.getParameterAnnotationAttributes(cp, param_annotations);
   640   /**
   684         if (attrs != null) {
   641    * Add an attribute to the code. Currently, the JVM knows about the
   685             for (final Attribute attr : attrs) {
   642    * LineNumberTable, LocalVariableTable and StackMap attributes,
   686                 addAttribute(attr);
   643    * where the former two will be generated automatically and the
   687             }
   644    * latter is used for the MIDP only. Other attributes will be
   688         }
   645    * ignored by the JVM but do no harm.
   689     }
   646    *
   690 
   647    * @param a attribute to be added
   691     /**
   648    */
   692      * Get method object. Never forget to call setMaxStack() or
   649   public void addCodeAttribute(Attribute a) { code_attrs_vec.add(a); }
   693      * setMaxStack(max), respectively, before calling this method (the same
   650 
   694      * applies for max locals).
   651   /**
   695      *
   652    * Remove a code attribute.
   696      * @return method object
   653    */
   697      */
   654   public void removeCodeAttribute(Attribute a) { code_attrs_vec.remove(a); }
   698     public Method getMethod() {
   655 
   699         final String signature = getSignature();
   656   /**
   700         final ConstantPoolGen _cp = super.getConstantPool();
   657    * Remove all code attributes.
   701         final int name_index = _cp.addUtf8(super.getName());
   658    */
   702         final int signature_index = _cp.addUtf8(signature);
   659   public void removeCodeAttributes() {
   703         /* Also updates positions of instructions, i.e., their indices
   660     code_attrs_vec.clear();
   704          */
   661   }
   705         byte[] byte_code = null;
   662 
   706         if (il != null) {
   663   /**
   707             byte_code = il.getByteCode();
   664    * @return all attributes of this method.
   708         }
   665    */
   709         LineNumberTable lnt = null;
   666   public Attribute[] getCodeAttributes() {
   710         LocalVariableTable lvt = null;
   667     Attribute[] attributes = new Attribute[code_attrs_vec.size()];
   711         LocalVariableTypeTable lvtt = null;
   668     code_attrs_vec.toArray(attributes);
   712 
   669     return attributes;
   713         /* Create LocalVariableTable, LocalvariableTypeTable, and LineNumberTable
   670   }
   714          * attributes (for debuggers, e.g.)
   671 
   715          */
   672   /**
   716         if ((variable_vec.size() > 0) && !strip_attributes) {
   673    * Get method object. Never forget to call setMaxStack() or setMaxStack(max), respectively,
   717             addCodeAttribute(lvt = getLocalVariableTable(_cp));
   674    * before calling this method (the same applies for max locals).
   718         }
   675    *
   719 
   676    * @return method object
   720         if ((type_vec.size() > 0) && !strip_attributes) {
   677    */
   721             addCodeAttribute(lvtt = getLocalVariableTypeTable(_cp));
   678   public Method getMethod() {
   722         }
   679     String signature       = getSignature();
   723 
   680     int    name_index      = cp.addUtf8(name);
   724         if ((line_number_vec.size() > 0) && !strip_attributes) {
   681     int    signature_index = cp.addUtf8(signature);
   725             addCodeAttribute(lnt = getLineNumberTable(_cp));
   682 
   726         }
   683     /* Also updates positions of instructions, i.e., their indices
   727         final Attribute[] code_attrs = getCodeAttributes();
   684      */
   728         /* Each attribute causes 6 additional header bytes
   685     byte[] byte_code = null;
   729          */
   686 
   730         int attrs_len = 0;
   687     if(il != null)
   731         for (final Attribute code_attr : code_attrs) {
   688       byte_code = il.getByteCode();
   732             attrs_len += code_attr.getLength() + 6;
   689 
   733         }
   690     LineNumberTable    lnt = null;
   734         final CodeException[] c_exc = getCodeExceptions();
   691     LocalVariableTable lvt = null;
   735         final int exc_len = c_exc.length * 8; // Every entry takes 8 bytes
   692     LocalVariableTypeTable lvtt = null;
   736         Code code = null;
   693 
   737         if ((il != null) && !isAbstract() && !isNative()) {
   694     /* Create LocalVariableTable, LocalvariableTypeTable, and LineNumberTable
   738             // Remove any stale code attribute
   695      * attributes (for debuggers, e.g.)
   739             final Attribute[] attributes = getAttributes();
   696      */
   740             for (final Attribute a : attributes) {
   697     if((variable_vec.size() > 0) && !strip_attributes)
   741                 if (a instanceof Code) {
   698       addCodeAttribute(lvt = getLocalVariableTable(cp));
   742                     removeAttribute(a);
   699 
   743                 }
   700     if((type_vec.size() > 0) && !strip_attributes)
   744             }
   701       addCodeAttribute(lvtt = getLocalVariableTypeTable(cp));
   745             code = new Code(_cp.addUtf8("Code"), 8 + byte_code.length + // prologue byte code
   702 
   746                     2 + exc_len + // exceptions
   703     if((line_number_vec.size() > 0) && !strip_attributes)
   747                     2 + attrs_len, // attributes
   704       addCodeAttribute(lnt = getLineNumberTable(cp));
   748                     max_stack, max_locals, byte_code, c_exc, code_attrs, _cp.getConstantPool());
   705 
   749             addAttribute(code);
   706     Attribute[] code_attrs = getCodeAttributes();
   750         }
   707 
   751         addAnnotationsAsAttribute(_cp);
   708     /* Each attribute causes 6 additional header bytes
   752         addParameterAnnotationsAsAttribute(_cp);
   709      */
   753         ExceptionTable et = null;
   710     int                attrs_len  = 0;
   754         if (throws_vec.size() > 0) {
   711     for(int i=0; i < code_attrs.length; i++)
   755             addAttribute(et = getExceptionTable(_cp));
   712       attrs_len += (code_attrs[i].getLength() + 6);
   756             // Add `Exceptions' if there are "throws" clauses
   713 
   757         }
   714     CodeException[] c_exc   = getCodeExceptions();
   758         final Method m = new Method(super.getAccessFlags(), name_index, signature_index, getAttributes(), _cp
   715     int             exc_len = c_exc.length * 8; // Every entry takes 8 bytes
   759                 .getConstantPool());
   716 
   760         // Undo effects of adding attributes
   717     Code code = null;
   761         if (lvt != null) {
   718 
   762             removeCodeAttribute(lvt);
   719     if((il != null) && !isAbstract()) {
   763         }
   720       // Remove any stale code attribute
   764         if (lvtt != null) {
   721       Attribute[] attributes = getAttributes();
   765             removeCodeAttribute(lvtt);
   722       for(int i=0; i < attributes.length; i++) {
   766         }
   723         Attribute a = attributes[i];
   767         if (lnt != null) {
   724 
   768             removeCodeAttribute(lnt);
   725         if(a instanceof Code)
   769         }
   726           removeAttribute(a);
   770         if (code != null) {
   727       }
   771             removeAttribute(code);
   728 
   772         }
   729       code = new Code(cp.addUtf8("Code"),
   773         if (et != null) {
   730                       8 + byte_code.length + // prologue byte code
   774             removeAttribute(et);
   731                       2 + exc_len +          // exceptions
   775         }
   732                       2 + attrs_len,         // attributes
   776         return m;
   733                       max_stack, max_locals,
   777     }
   734                       byte_code, c_exc,
   778 
   735                       code_attrs,
   779     /**
   736                       cp.getConstantPool());
   780      * Remove all NOPs from the instruction list (if possible) and update every
   737 
   781      * object referring to them, i.e., branch instructions, local variables and
   738       addAttribute(code);
   782      * exception handlers.
   739     }
   783      */
   740 
   784     public void removeNOPs() {
   741     ExceptionTable et = null;
   785         if (il != null) {
   742 
   786             InstructionHandle next;
   743     if(throws_vec.size() > 0)
   787             /* Check branch instructions.
   744       addAttribute(et = getExceptionTable(cp)); // Add `Exceptions' if there are "throws" clauses
   788              */
   745 
   789             for (InstructionHandle ih = il.getStart(); ih != null; ih = next) {
   746     Method m = new Method(access_flags, name_index, signature_index,
   790                 next = ih.getNext();
   747                           getAttributes(), cp.getConstantPool());
   791                 if ((next != null) && (ih.getInstruction() instanceof NOP)) {
   748 
   792                     try {
   749     // Undo effects of adding attributes
   793                         il.delete(ih);
   750     if(lvt != null)  removeCodeAttribute(lvt);
   794                     } catch (final TargetLostException e) {
   751     if(lvtt != null) removeCodeAttribute(lvtt);
   795                         for (final InstructionHandle target : e.getTargets()) {
   752     if(lnt != null)  removeCodeAttribute(lnt);
   796                             for (final InstructionTargeter targeter : target.getTargeters()) {
   753     if(code != null) removeAttribute(code);
   797                                 targeter.updateTarget(target, next);
   754     if(et != null)   removeAttribute(et);
   798                             }
   755 
   799                         }
   756     return m;
   800                     }
   757   }
   801                 }
   758 
   802             }
   759   /**
   803         }
   760    * Remove all NOPs from the instruction list (if possible) and update every
   804     }
   761    * object refering to them, i.e., branch instructions, local variables and
   805 
   762    * exception handlers.
   806     /**
   763    */
   807      * Set maximum number of local variables.
   764   public void removeNOPs() {
   808      */
   765     if(il != null) {
   809     public void setMaxLocals(final int m) {
   766       InstructionHandle next;
   810         max_locals = m;
   767       /* Check branch instructions.
   811     }
   768        */
   812 
   769       for(InstructionHandle ih = il.getStart(); ih != null; ih = next) {
   813     public int getMaxLocals() {
   770         next = ih.next;
   814         return max_locals;
   771 
   815     }
   772         if((next != null) && (ih.getInstruction() instanceof NOP)) {
   816 
   773           try {
   817     /**
   774             il.delete(ih);
   818      * Set maximum stack size for this method.
   775           } catch(TargetLostException e) {
   819      */
   776             InstructionHandle[] targets = e.getTargets();
   820     public void setMaxStack(final int m) { // TODO could be package-protected?
   777 
   821         max_stack = m;
   778             for(int i=0; i < targets.length; i++) {
   822     }
   779               InstructionTargeter[] targeters = targets[i].getTargeters();
   823 
   780 
   824     public int getMaxStack() {
   781               for(int j=0; j < targeters.length; j++)
   825         return max_stack;
   782                 targeters[j].updateTarget(targets[i], next);
   826     }
   783             }
   827 
   784           }
   828     /**
   785         }
   829      * @return class that contains this method
   786       }
   830      */
   787     }
   831     public String getClassName() {
   788   }
   832         return class_name;
   789 
   833     }
   790   /**
   834 
   791    * Set maximum number of local variables.
   835     public void setClassName(final String class_name) { // TODO could be package-protected?
   792    */
   836         this.class_name = class_name;
   793   public void   setMaxLocals(int m)  { max_locals = m; }
   837     }
   794   public int    getMaxLocals()       { return max_locals; }
   838 
   795 
   839     public void setReturnType(final Type return_type) {
   796   /**
   840         setType(return_type);
   797    * Set maximum stack size for this method.
   841     }
   798    */
   842 
   799   public void   setMaxStack(int m)  { max_stack = m; }
   843     public Type getReturnType() {
   800   public int    getMaxStack()       { return max_stack; }
   844         return getType();
   801 
   845     }
   802   /** @return class that contains this method
   846 
   803    */
   847     public void setArgumentTypes(final Type[] arg_types) {
   804   public String getClassName()                     { return class_name; }
   848         this.arg_types = arg_types;
   805   public void   setClassName(String class_name)    { this.class_name = class_name; }
   849     }
   806 
   850 
   807   public void   setReturnType(Type return_type)    { setType(return_type); }
   851     public Type[] getArgumentTypes() {
   808   public Type   getReturnType()                    { return getType(); }
   852         return arg_types.clone();
   809 
   853     }
   810   public void   setArgumentTypes(Type[] arg_types)  { this.arg_types = arg_types; }
   854 
   811   public Type[] getArgumentTypes()                  { return (Type[])arg_types.clone(); }
   855     public void setArgumentType(final int i, final Type type) {
   812   public void   setArgumentType(int i, Type type)       { arg_types[i] = type; }
   856         arg_types[i] = type;
   813   public Type   getArgumentType(int i)                  { return arg_types[i]; }
   857     }
   814 
   858 
   815   public void     setArgumentNames(String[] arg_names) { this.arg_names = arg_names; }
   859     public Type getArgumentType(final int i) {
   816   public String[] getArgumentNames()                   { return (String[])arg_names.clone(); }
   860         return arg_types[i];
   817   public void     setArgumentName(int i, String name)     { arg_names[i] = name; }
   861     }
   818   public String   getArgumentName(int i)                  { return arg_names[i]; }
   862 
   819 
   863     public void setArgumentNames(final String[] arg_names) {
   820   public InstructionList getInstructionList()                    { return il; }
   864         this.arg_names = arg_names;
   821   public void            setInstructionList(InstructionList il)  { this.il = il; }
   865     }
   822 
   866 
   823   public String getSignature() {
   867     public String[] getArgumentNames() {
   824     return Type.getMethodSignature(type, arg_types);
   868         return arg_names.clone();
   825   }
   869     }
   826 
   870 
   827   /**
   871     public void setArgumentName(final int i, final String name) {
   828    * Computes max. stack size by performing control flow analysis.
   872         arg_names[i] = name;
   829    */
   873     }
   830   public void setMaxStack() {
   874 
   831     if(il != null)
   875     public String getArgumentName(final int i) {
   832       max_stack = getMaxStack(cp, il, getExceptionHandlers());
   876         return arg_names[i];
   833     else
   877     }
   834       max_stack = 0;
   878 
   835   }
   879     public InstructionList getInstructionList() {
   836 
   880         return il;
   837   /**
   881     }
   838    * Compute maximum number of local variables.
   882 
   839    */
   883     public void setInstructionList(final InstructionList il) { // TODO could be package-protected?
   840   public void setMaxLocals() {
   884         this.il = il;
   841     if(il != null) {
   885     }
   842       int max = isStatic()? 0 : 1;
   886 
   843 
   887     @Override
   844       if(arg_types != null)
   888     public String getSignature() {
   845         for(int i=0; i < arg_types.length; i++)
   889         return Type.getMethodSignature(super.getType(), arg_types);
   846           max += arg_types[i].getSize();
   890     }
   847 
   891 
   848       for(InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
   892     /**
   849         Instruction ins = ih.getInstruction();
   893      * Computes max. stack size by performing control flow analysis.
   850 
   894      */
   851         if((ins instanceof LocalVariableInstruction) ||
   895     public void setMaxStack() { // TODO could be package-protected? (some tests would need repackaging)
   852            (ins instanceof RET) || (ins instanceof IINC))
   896         if (il != null) {
   853         {
   897             max_stack = getMaxStack(super.getConstantPool(), il, getExceptionHandlers());
   854           int index = ((IndexedInstruction)ins).getIndex() +
   898         } else {
   855             ((TypedInstruction)ins).getType(cp).getSize();
   899             max_stack = 0;
   856 
   900         }
   857           if(index > max)
   901     }
   858             max = index;
   902 
   859         }
   903     /**
   860       }
   904      * Compute maximum number of local variables.
   861 
   905      */
   862       max_locals = max;
   906     public void setMaxLocals() { // TODO could be package-protected? (some tests would need repackaging)
   863     } else
   907         if (il != null) {
   864       max_locals = 0;
   908             int max = isStatic() ? 0 : 1;
   865   }
   909             if (arg_types != null) {
   866 
   910                 for (final Type arg_type : arg_types) {
   867   /** Do not/Do produce attributes code attributesLineNumberTable and
   911                     max += arg_type.getSize();
   868    * LocalVariableTable, like javac -O
   912                 }
   869    */
   913             }
   870   public void stripAttributes(boolean flag) { strip_attributes = flag; }
   914             for (InstructionHandle ih = il.getStart(); ih != null; ih = ih.getNext()) {
   871 
   915                 final Instruction ins = ih.getInstruction();
   872   static final class BranchTarget {
   916                 if ((ins instanceof LocalVariableInstruction) || (ins instanceof RET)
   873     InstructionHandle target;
   917                         || (ins instanceof IINC)) {
   874     int               stackDepth;
   918                     final int index = ((IndexedInstruction) ins).getIndex()
   875 
   919                             + ((TypedInstruction) ins).getType(super.getConstantPool()).getSize();
   876     BranchTarget(InstructionHandle target, int stackDepth) {
   920                     if (index > max) {
   877       this.target = target;
   921                         max = index;
   878       this.stackDepth = stackDepth;
   922                     }
   879     }
   923                 }
   880   }
   924             }
   881 
   925             max_locals = max;
   882   static final class BranchStack {
   926         } else {
   883     Stack     branchTargets  = new Stack();
   927             max_locals = 0;
   884     Hashtable visitedTargets = new Hashtable();
   928         }
   885 
   929     }
   886     public void push(InstructionHandle target, int stackDepth) {
   930 
   887       if(visited(target))
   931     /**
   888         return;
   932      * Do not/Do produce attributes code attributesLineNumberTable and
   889 
   933      * LocalVariableTable, like javac -O
   890       branchTargets.push(visit(target, stackDepth));
   934      */
   891     }
   935     public void stripAttributes(final boolean flag) {
   892 
   936         strip_attributes = flag;
   893     public BranchTarget pop() {
   937     }
   894       if(!branchTargets.empty()) {
   938 
   895         BranchTarget bt = (BranchTarget) branchTargets.pop();
   939     static final class BranchTarget {
   896         return bt;
   940 
   897       }
   941         final InstructionHandle target;
   898 
   942         final int stackDepth;
   899       return null;
   943 
   900     }
   944         BranchTarget(final InstructionHandle target, final int stackDepth) {
   901 
   945             this.target = target;
   902     private final BranchTarget visit(InstructionHandle target, int stackDepth) {
   946             this.stackDepth = stackDepth;
   903       BranchTarget bt = new BranchTarget(target, stackDepth);
   947         }
   904       visitedTargets.put(target, bt);
   948     }
   905 
   949 
   906       return bt;
   950     static final class BranchStack {
   907     }
   951 
   908 
   952         private final Stack<BranchTarget> branchTargets = new Stack<>();
   909     private final boolean visited(InstructionHandle target) {
   953         private final Map<InstructionHandle, BranchTarget> visitedTargets = new HashMap<>();
   910       return (visitedTargets.get(target) != null);
   954 
   911     }
   955         public void push(final InstructionHandle target, final int stackDepth) {
   912   }
   956             if (visited(target)) {
   913 
   957                 return;
   914   /**
   958             }
   915    * Computes stack usage of an instruction list by performing control flow analysis.
   959             branchTargets.push(visit(target, stackDepth));
   916    *
   960         }
   917    * @return maximum stack depth used by method
   961 
   918    */
   962         public BranchTarget pop() {
   919   public static int getMaxStack(ConstantPoolGen cp, InstructionList il, CodeExceptionGen[] et) {
   963             if (!branchTargets.empty()) {
   920     BranchStack branchTargets = new BranchStack();
   964                 final BranchTarget bt = branchTargets.pop();
   921 
   965                 return bt;
   922     /* Initially, populate the branch stack with the exception
   966             }
   923      * handlers, because these aren't (necessarily) branched to
   967             return null;
   924      * explicitly. in each case, the stack will have depth 1,
   968         }
   925      * containing the exception object.
   969 
   926      */
   970         private BranchTarget visit(final InstructionHandle target, final int stackDepth) {
   927     for (int i = 0; i < et.length; i++) {
   971             final BranchTarget bt = new BranchTarget(target, stackDepth);
   928       InstructionHandle handler_pc = et[i].getHandlerPC();
   972             visitedTargets.put(target, bt);
   929       if (handler_pc != null)
   973             return bt;
   930         branchTargets.push(handler_pc, 1);
   974         }
   931     }
   975 
   932 
   976         private boolean visited(final InstructionHandle target) {
   933     int               stackDepth = 0, maxStackDepth = 0;
   977             return visitedTargets.get(target) != null;
   934     InstructionHandle ih         = il.getStart();
   978         }
   935 
   979     }
   936     while(ih != null) {
   980 
   937       Instruction instruction = ih.getInstruction();
   981     /**
   938       short opcode = instruction.getOpcode();
   982      * Computes stack usage of an instruction list by performing control flow
   939       int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
   983      * analysis.
   940 
   984      *
   941       stackDepth += delta;
   985      * @return maximum stack depth used by method
   942       if(stackDepth > maxStackDepth)
   986      */
   943         maxStackDepth = stackDepth;
   987     public static int getMaxStack(final ConstantPoolGen cp, final InstructionList il,
   944 
   988             final CodeExceptionGen[] et) {
   945       // choose the next instruction based on whether current is a branch.
   989         final BranchStack branchTargets = new BranchStack();
   946       if(instruction instanceof BranchInstruction) {
   990         /* Initially, populate the branch stack with the exception
   947         BranchInstruction branch = (BranchInstruction) instruction;
   991          * handlers, because these aren't (necessarily) branched to
   948         if(instruction instanceof Select) {
   992          * explicitly. in each case, the stack will have depth 1,
   949           // explore all of the select's targets. the default target is handled below.
   993          * containing the exception object.
   950           Select select = (Select) branch;
   994          */
   951           InstructionHandle[] targets = select.getTargets();
   995         for (final CodeExceptionGen element : et) {
   952           for (int i = 0; i < targets.length; i++)
   996             final InstructionHandle handler_pc = element.getHandlerPC();
   953             branchTargets.push(targets[i], stackDepth);
   997             if (handler_pc != null) {
   954           // nothing to fall through to.
   998                 branchTargets.push(handler_pc, 1);
   955           ih = null;
   999             }
   956         } else if(!(branch instanceof IfInstruction)) {
  1000         }
   957           // if an instruction that comes back to following PC,
  1001         int stackDepth = 0;
   958           // push next instruction, with stack depth reduced by 1.
  1002         int maxStackDepth = 0;
   959           if(opcode == Constants.JSR || opcode == Constants.JSR_W)
  1003         InstructionHandle ih = il.getStart();
   960             branchTargets.push(ih.getNext(), stackDepth - 1);
  1004         while (ih != null) {
   961           ih = null;
  1005             final Instruction instruction = ih.getInstruction();
   962         }
  1006             final short opcode = instruction.getOpcode();
   963         // for all branches, the target of the branch is pushed on the branch stack.
  1007             final int delta = instruction.produceStack(cp) - instruction.consumeStack(cp);
   964         // conditional branches have a fall through case, selects don't, and
  1008             stackDepth += delta;
   965         // jsr/jsr_w return to the next instruction.
  1009             if (stackDepth > maxStackDepth) {
   966         branchTargets.push(branch.getTarget(), stackDepth);
  1010                 maxStackDepth = stackDepth;
   967       } else {
  1011             }
   968         // check for instructions that terminate the method.
  1012             // choose the next instruction based on whether current is a branch.
   969         if(opcode == Constants.ATHROW || opcode == Constants.RET ||
  1013             if (instruction instanceof BranchInstruction) {
   970            (opcode >= Constants.IRETURN && opcode <= Constants.RETURN))
  1014                 final BranchInstruction branch = (BranchInstruction) instruction;
   971           ih = null;
  1015                 if (instruction instanceof Select) {
   972       }
  1016                     // explore all of the select's targets. the default target is handled below.
   973       // normal case, go to the next instruction.
  1017                     final Select select = (Select) branch;
   974       if(ih != null)
  1018                     final InstructionHandle[] targets = select.getTargets();
   975         ih = ih.getNext();
  1019                     for (final InstructionHandle target : targets) {
   976       // if we have no more instructions, see if there are any deferred branches to explore.
  1020                         branchTargets.push(target, stackDepth);
   977       if(ih == null) {
  1021                     }
   978         BranchTarget bt = branchTargets.pop();
  1022                     // nothing to fall through to.
   979         if (bt != null) {
  1023                     ih = null;
   980           ih = bt.target;
  1024                 } else if (!(branch instanceof IfInstruction)) {
   981           stackDepth = bt.stackDepth;
  1025                     // if an instruction that comes back to following PC,
   982         }
  1026                     // push next instruction, with stack depth reduced by 1.
   983       }
  1027                     if (opcode == Const.JSR || opcode == Const.JSR_W) {
   984     }
  1028                         branchTargets.push(ih.getNext(), stackDepth - 1);
   985 
  1029                     }
   986     return maxStackDepth;
  1030                     ih = null;
   987   }
  1031                 }
   988 
  1032                 // for all branches, the target of the branch is pushed on the branch stack.
   989   private ArrayList observers;
  1033                 // conditional branches have a fall through case, selects don't, and
   990 
  1034                 // jsr/jsr_w return to the next instruction.
   991   /** Add observer for this object.
  1035                 branchTargets.push(branch.getTarget(), stackDepth);
   992    */
  1036             } else {
   993   public void addObserver(MethodObserver o) {
  1037                 // check for instructions that terminate the method.
   994     if(observers == null)
  1038                 if (opcode == Const.ATHROW || opcode == Const.RET
   995       observers = new ArrayList();
  1039                         || (opcode >= Const.IRETURN && opcode <= Const.RETURN)) {
   996 
  1040                     ih = null;
   997     observers.add(o);
  1041                 }
   998   }
  1042             }
   999 
  1043             // normal case, go to the next instruction.
  1000   /** Remove observer for this object.
  1044             if (ih != null) {
  1001    */
  1045                 ih = ih.getNext();
  1002   public void removeObserver(MethodObserver o) {
  1046             }
  1003     if(observers != null)
  1047             // if we have no more instructions, see if there are any deferred branches to explore.
  1004       observers.remove(o);
  1048             if (ih == null) {
  1005   }
  1049                 final BranchTarget bt = branchTargets.pop();
  1006 
  1050                 if (bt != null) {
  1007   /** Call notify() method on all observers. This method is not called
  1051                     ih = bt.target;
  1008    * automatically whenever the state has changed, but has to be
  1052                     stackDepth = bt.stackDepth;
  1009    * called by the user after he has finished editing the object.
  1053                 }
  1010    */
  1054             }
  1011   public void update() {
  1055         }
  1012     if(observers != null)
  1056         return maxStackDepth;
  1013       for(Iterator e = observers.iterator(); e.hasNext(); )
  1057     }
  1014         ((MethodObserver)e.next()).notify(this);
  1058 
  1015   }
  1059     private List<MethodObserver> observers;
  1016 
  1060 
  1017   /**
  1061     /**
  1018    * Return string representation close to declaration format,
  1062      * Add observer for this object.
  1019    * `public static void _main(String[]) throws IOException', e.g.
  1063      */
  1020    *
  1064     public void addObserver(final MethodObserver o) {
  1021    * @return String representation of the method.
  1065         if (observers == null) {
  1022    */
  1066             observers = new ArrayList<>();
  1023   public final String toString() {
  1067         }
  1024     String access    = Utility.accessToString(access_flags);
  1068         observers.add(o);
  1025     String signature = Type.getMethodSignature(type, arg_types);
  1069     }
  1026 
  1070 
  1027     signature = Utility.methodSignatureToString(signature, name, access,
  1071     /**
  1028                                                 true, getLocalVariableTable(cp));
  1072      * Remove observer for this object.
  1029 
  1073      */
  1030     StringBuffer buf = new StringBuffer(signature);
  1074     public void removeObserver(final MethodObserver o) {
  1031 
  1075         if (observers != null) {
  1032     if(throws_vec.size() > 0) {
  1076             observers.remove(o);
  1033       for(Iterator e = throws_vec.iterator(); e.hasNext(); )
  1077         }
  1034         buf.append("\n\t\tthrows " + e.next());
  1078     }
  1035     }
  1079 
  1036 
  1080     /**
  1037     return buf.toString();
  1081      * Call notify() method on all observers. This method is not called
  1038   }
  1082      * automatically whenever the state has changed, but has to be called by the
  1039 
  1083      * user after he has finished editing the object.
  1040   /** @return deep copy of this method
  1084      */
  1041    */
  1085     public void update() {
  1042   public MethodGen copy(String class_name, ConstantPoolGen cp) {
  1086         if (observers != null) {
  1043     Method    m  = ((MethodGen)clone()).getMethod();
  1087             for (final MethodObserver observer : observers) {
  1044     MethodGen mg = new MethodGen(m, class_name, this.cp);
  1088                 observer.notify(this);
  1045 
  1089             }
  1046     if(this.cp != cp) {
  1090         }
  1047       mg.setConstantPool(cp);
  1091     }
  1048       mg.getInstructionList().replaceConstantPool(this.cp, cp);
  1092 
  1049     }
  1093     /**
  1050 
  1094      * Return string representation close to declaration format, e.g. public
  1051     return mg;
  1095      * static void main(String[]) throws IOException'
  1052   }
  1096      *
       
  1097      * @return String representation of the method.
       
  1098      */
       
  1099     @Override
       
  1100     public final String toString() {
       
  1101         final String access = Utility.accessToString(super.getAccessFlags());
       
  1102         String signature = Type.getMethodSignature(super.getType(), arg_types);
       
  1103         signature = Utility.methodSignatureToString(signature, super.getName(), access, true,
       
  1104                 getLocalVariableTable(super.getConstantPool()));
       
  1105         final StringBuilder buf = new StringBuilder(signature);
       
  1106         for (final Attribute a : getAttributes()) {
       
  1107             if (!((a instanceof Code) || (a instanceof ExceptionTable))) {
       
  1108                 buf.append(" [").append(a).append("]");
       
  1109             }
       
  1110         }
       
  1111 
       
  1112         if (throws_vec.size() > 0) {
       
  1113             for (final String throwsDescriptor : throws_vec) {
       
  1114                 buf.append("\n\t\tthrows ").append(throwsDescriptor);
       
  1115             }
       
  1116         }
       
  1117         return buf.toString();
       
  1118     }
       
  1119 
       
  1120     /**
       
  1121      * @return deep copy of this method
       
  1122      */
       
  1123     public MethodGen copy(final String class_name, final ConstantPoolGen cp) {
       
  1124         final Method m = ((MethodGen) clone()).getMethod();
       
  1125         final MethodGen mg = new MethodGen(m, class_name, super.getConstantPool());
       
  1126         if (super.getConstantPool() != cp) {
       
  1127             mg.setConstantPool(cp);
       
  1128             mg.getInstructionList().replaceConstantPool(super.getConstantPool(), cp);
       
  1129         }
       
  1130         return mg;
       
  1131     }
       
  1132 
       
  1133     //J5TODO: Should param_annotations be an array of arrays? Rather than an array of lists, this
       
  1134     // is more likely to suggest to the caller it is readonly (which a List does not).
       
  1135     /**
       
  1136      * Return a list of AnnotationGen objects representing parameter annotations
       
  1137      *
       
  1138      * @since 6.0
       
  1139      */
       
  1140     public List<AnnotationEntryGen> getAnnotationsOnParameter(final int i) {
       
  1141         ensureExistingParameterAnnotationsUnpacked();
       
  1142         if (!hasParameterAnnotations || i > arg_types.length) {
       
  1143             return null;
       
  1144         }
       
  1145         return param_annotations[i];
       
  1146     }
       
  1147 
       
  1148     /**
       
  1149      * Goes through the attributes on the method and identifies any that are
       
  1150      * RuntimeParameterAnnotations, extracting their contents and storing them
       
  1151      * as parameter annotations. There are two kinds of parameter annotation -
       
  1152      * visible and invisible. Once they have been unpacked, these attributes are
       
  1153      * deleted. (The annotations will be rebuilt as attributes when someone
       
  1154      * builds a Method object out of this MethodGen object).
       
  1155      */
       
  1156     private void ensureExistingParameterAnnotationsUnpacked() {
       
  1157         if (haveUnpackedParameterAnnotations) {
       
  1158             return;
       
  1159         }
       
  1160         // Find attributes that contain parameter annotation data
       
  1161         final Attribute[] attrs = getAttributes();
       
  1162         ParameterAnnotations paramAnnVisAttr = null;
       
  1163         ParameterAnnotations paramAnnInvisAttr = null;
       
  1164         for (final Attribute attribute : attrs) {
       
  1165             if (attribute instanceof ParameterAnnotations) {
       
  1166                 // Initialize param_annotations
       
  1167                 if (!hasParameterAnnotations) {
       
  1168                     @SuppressWarnings("unchecked") // OK
       
  1169                     final List<AnnotationEntryGen>[] parmList = new List[arg_types.length];
       
  1170                     param_annotations = parmList;
       
  1171                     for (int j = 0; j < arg_types.length; j++) {
       
  1172                         param_annotations[j] = new ArrayList<>();
       
  1173                     }
       
  1174                 }
       
  1175                 hasParameterAnnotations = true;
       
  1176                 final ParameterAnnotations rpa = (ParameterAnnotations) attribute;
       
  1177                 if (rpa instanceof RuntimeVisibleParameterAnnotations) {
       
  1178                     paramAnnVisAttr = rpa;
       
  1179                 } else {
       
  1180                     paramAnnInvisAttr = rpa;
       
  1181                 }
       
  1182                 for (int j = 0; j < arg_types.length; j++) {
       
  1183                     // This returns Annotation[] ...
       
  1184                     final ParameterAnnotationEntry immutableArray = rpa
       
  1185                             .getParameterAnnotationEntries()[j];
       
  1186                     // ... which needs transforming into an AnnotationGen[] ...
       
  1187                     final List<AnnotationEntryGen> mutable
       
  1188                             = makeMutableVersion(immutableArray.getAnnotationEntries());
       
  1189                     // ... then add these to any we already know about
       
  1190                     param_annotations[j].addAll(mutable);
       
  1191                 }
       
  1192             }
       
  1193         }
       
  1194         if (paramAnnVisAttr != null) {
       
  1195             removeAttribute(paramAnnVisAttr);
       
  1196         }
       
  1197         if (paramAnnInvisAttr != null) {
       
  1198             removeAttribute(paramAnnInvisAttr);
       
  1199         }
       
  1200         haveUnpackedParameterAnnotations = true;
       
  1201     }
       
  1202 
       
  1203     private List<AnnotationEntryGen> makeMutableVersion(final AnnotationEntry[] mutableArray) {
       
  1204         final List<AnnotationEntryGen> result = new ArrayList<>();
       
  1205         for (final AnnotationEntry element : mutableArray) {
       
  1206             result.add(new AnnotationEntryGen(element, getConstantPool(),
       
  1207                     false));
       
  1208         }
       
  1209         return result;
       
  1210     }
       
  1211 
       
  1212     public void addParameterAnnotation(final int parameterIndex,
       
  1213             final AnnotationEntryGen annotation) {
       
  1214         ensureExistingParameterAnnotationsUnpacked();
       
  1215         if (!hasParameterAnnotations) {
       
  1216             @SuppressWarnings("unchecked") // OK
       
  1217             final List<AnnotationEntryGen>[] parmList = new List[arg_types.length];
       
  1218             param_annotations = parmList;
       
  1219             hasParameterAnnotations = true;
       
  1220         }
       
  1221         final List<AnnotationEntryGen> existingAnnotations = param_annotations[parameterIndex];
       
  1222         if (existingAnnotations != null) {
       
  1223             existingAnnotations.add(annotation);
       
  1224         } else {
       
  1225             final List<AnnotationEntryGen> l = new ArrayList<>();
       
  1226             l.add(annotation);
       
  1227             param_annotations[parameterIndex] = l;
       
  1228         }
       
  1229     }
       
  1230 
       
  1231     /**
       
  1232      * @return Comparison strategy object
       
  1233      */
       
  1234     public static BCELComparator getComparator() {
       
  1235         return bcelComparator;
       
  1236     }
       
  1237 
       
  1238     /**
       
  1239      * @param comparator Comparison strategy object
       
  1240      */
       
  1241     public static void setComparator(final BCELComparator comparator) {
       
  1242         bcelComparator = comparator;
       
  1243     }
       
  1244 
       
  1245     /**
       
  1246      * Return value as defined by given BCELComparator strategy. By default two
       
  1247      * MethodGen objects are said to be equal when their names and signatures
       
  1248      * are equal.
       
  1249      *
       
  1250      * @see java.lang.Object#equals(java.lang.Object)
       
  1251      */
       
  1252     @Override
       
  1253     public boolean equals(final Object obj) {
       
  1254         return bcelComparator.equals(this, obj);
       
  1255     }
       
  1256 
       
  1257     /**
       
  1258      * Return value as defined by given BCELComparator strategy. By default
       
  1259      * return the hashcode of the method's name XOR signature.
       
  1260      *
       
  1261      * @see java.lang.Object#hashCode()
       
  1262      */
       
  1263     @Override
       
  1264     public int hashCode() {
       
  1265         return bcelComparator.hashCode(this);
       
  1266     }
  1053 }
  1267 }