Home | History | Annotate | Download | only in optimize
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2014 Eric Lafortune (eric (at) graphics.cornell.edu)
      6  *
      7  * This program is free software; you can redistribute it and/or modify it
      8  * under the terms of the GNU General Public License as published by the Free
      9  * Software Foundation; either version 2 of the License, or (at your option)
     10  * any later version.
     11  *
     12  * This program is distributed in the hope that it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
     15  * more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, write to the Free Software Foundation, Inc.,
     19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
     20  */
     21 package proguard.optimize;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.attribute.annotation.*;
     26 import proguard.classfile.attribute.visitor.AttributeVisitor;
     27 import proguard.classfile.editor.ConstantPoolEditor;
     28 import proguard.classfile.util.*;
     29 import proguard.classfile.visitor.MemberVisitor;
     30 
     31 /**
     32  * This MemberVisitor adds an additional parameter to the duplicate
     33  * initialization methods that it visits.
     34  */
     35 public class DuplicateInitializerFixer
     36 extends      SimplifiedVisitor
     37 implements   MemberVisitor,
     38              AttributeVisitor
     39 {
     40     private static final boolean DEBUG = false;
     41 
     42     private static final char[] TYPES = new char[]
     43     {
     44         ClassConstants.TYPE_BYTE,
     45         ClassConstants.TYPE_CHAR,
     46         ClassConstants.TYPE_SHORT,
     47         ClassConstants.TYPE_INT,
     48         ClassConstants.TYPE_BOOLEAN
     49     };
     50 
     51 
     52     private final MemberVisitor extraFixedInitializerVisitor;
     53 
     54 
     55     /**
     56      * Creates a new DuplicateInitializerFixer.
     57      */
     58     public DuplicateInitializerFixer()
     59     {
     60         this(null);
     61     }
     62 
     63 
     64     /**
     65      * Creates a new DuplicateInitializerFixer with an extra visitor.
     66      * @param extraFixedInitializerVisitor an optional extra visitor for all
     67      *                                     initializers that have been fixed.
     68      */
     69     public DuplicateInitializerFixer(MemberVisitor extraFixedInitializerVisitor)
     70     {
     71         this.extraFixedInitializerVisitor = extraFixedInitializerVisitor;
     72     }
     73 
     74 
     75     // Implementations for MemberVisitor.
     76 
     77     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
     78     {
     79         // Is it a class instance initializer?
     80         String name = programMethod.getName(programClass);
     81         if (name.equals(ClassConstants.METHOD_NAME_INIT))
     82         {
     83             // Is there already another initializer with the same descriptor?
     84             String descriptor    = programMethod.getDescriptor(programClass);
     85             Method similarMethod = programClass.findMethod(name, descriptor);
     86             if (!programMethod.equals(similarMethod))
     87             {
     88                 // Should this initializer be preserved?
     89                 if (KeepMarker.isKept(programMethod))
     90                 {
     91                     // Fix the other initializer.
     92                     programMethod = (ProgramMethod)similarMethod;
     93                 }
     94 
     95                 int index = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE);
     96 
     97                 // Try to find a new, unique descriptor.
     98                 int typeCounter = 0;
     99                 while (true)
    100                 {
    101                     // Construct the new descriptor by inserting a new type
    102                     // as an additional last argument.
    103                     StringBuffer newDescriptorBuffer =
    104                         new StringBuffer(descriptor.substring(0, index));
    105 
    106                     for (int arrayDimension = 0; arrayDimension < typeCounter / TYPES.length; arrayDimension++)
    107                     {
    108                         newDescriptorBuffer.append(ClassConstants.TYPE_ARRAY);
    109                     }
    110 
    111                     newDescriptorBuffer.append(TYPES[typeCounter % TYPES.length]);
    112                     newDescriptorBuffer.append(descriptor.substring(index));
    113 
    114                     String newDescriptor = newDescriptorBuffer.toString();
    115 
    116                     // Is the new initializer descriptor unique?
    117                     if (programClass.findMethod(name, newDescriptor) == null)
    118                     {
    119                         if (DEBUG)
    120                         {
    121                             System.out.println("DuplicateInitializerFixer:");
    122                             System.out.println("  ["+programClass.getName()+"."+name+descriptor+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") -> ["+newDescriptor+"]");
    123                         }
    124 
    125                         // Update the descriptor.
    126                         programMethod.u2descriptorIndex =
    127                             new ConstantPoolEditor(programClass).addUtf8Constant(newDescriptor);
    128 
    129                         // Fix the local variable frame size, the method
    130                         // signature, and the parameter annotations, if
    131                         // necessary.
    132                         programMethod.attributesAccept(programClass,
    133                                                        this);
    134 
    135                         // Visit the initializer, if required.
    136                         if (extraFixedInitializerVisitor != null)
    137                         {
    138                             extraFixedInitializerVisitor.visitProgramMethod(programClass, programMethod);
    139                         }
    140 
    141                         // We're done with this constructor.
    142                         return;
    143                     }
    144 
    145                     typeCounter++;
    146                 }
    147             }
    148         }
    149     }
    150 
    151 
    152     // Implementations for AttributeVisitor.
    153 
    154     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
    155 
    156 
    157     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
    158     {
    159         // The minimum variable size is determined by the arguments.
    160         int maxLocals =
    161             ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz),
    162                                                   method.getAccessFlags());
    163 
    164         if (codeAttribute.u2maxLocals < maxLocals)
    165         {
    166             codeAttribute.u2maxLocals = maxLocals;
    167         }
    168     }
    169 
    170 
    171     public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute)
    172     {
    173         String descriptor      = method.getDescriptor(clazz);
    174         int    descriptorIndex = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE);
    175         String signature       = signatureAttribute.getSignature(clazz);
    176         int    signatureIndex  = signature.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE);
    177 
    178         String newSignature = signature.substring(0, signatureIndex) +
    179                               descriptor.charAt(descriptorIndex - 1) +
    180                               signature.substring(signatureIndex);
    181 
    182         // Update the signature.
    183         signatureAttribute.u2signatureIndex =
    184             new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature);
    185     }
    186 
    187 
    188     public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
    189     {
    190         // Update the number of parameters.
    191         int oldParametersCount = parameterAnnotationsAttribute.u1parametersCount++;
    192 
    193         if (parameterAnnotationsAttribute.u2parameterAnnotationsCount == null ||
    194             parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u1parametersCount)
    195         {
    196             int[]          annotationsCounts = new int[parameterAnnotationsAttribute.u1parametersCount];
    197             Annotation[][] annotations       = new Annotation[parameterAnnotationsAttribute.u1parametersCount][];
    198 
    199             System.arraycopy(parameterAnnotationsAttribute.u2parameterAnnotationsCount,
    200                              0,
    201                              annotationsCounts,
    202                              0,
    203                              oldParametersCount);
    204 
    205             System.arraycopy(parameterAnnotationsAttribute.parameterAnnotations,
    206                              0,
    207                              annotations,
    208                              0,
    209                              oldParametersCount);
    210 
    211             parameterAnnotationsAttribute.u2parameterAnnotationsCount = annotationsCounts;
    212             parameterAnnotationsAttribute.parameterAnnotations        = annotations;
    213         }
    214     }
    215 }