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