Home | History | Annotate | Download | only in info
      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.info;
     22 
     23 import proguard.classfile.*;
     24 import proguard.classfile.attribute.*;
     25 import proguard.classfile.attribute.visitor.AttributeVisitor;
     26 import proguard.classfile.instruction.*;
     27 import proguard.classfile.instruction.visitor.InstructionVisitor;
     28 import proguard.classfile.util.*;
     29 import proguard.classfile.visitor.MemberVisitor;
     30 import proguard.evaluation.value.Value;
     31 import proguard.optimize.evaluation.PartialEvaluator;
     32 
     33 /**
     34  * This MemberVisitor counts the parameters and marks the used parameters
     35  * of the methods that it visits. It also marks the 'this' parameters of
     36  * methods that have hierarchies.
     37  *
     38  * @author Eric Lafortune
     39  */
     40 public class ParameterUsageMarker
     41 extends      SimplifiedVisitor
     42 implements   MemberVisitor,
     43              AttributeVisitor,
     44              InstructionVisitor
     45 {
     46     private static final boolean DEBUG = false;
     47 
     48 
     49     private final boolean          markThisParameter;
     50     private final boolean          markAllParameters;
     51     private final PartialEvaluator partialEvaluator = new PartialEvaluator();
     52 
     53 
     54     /**
     55      * Creates a new ParameterUsageMarker.
     56      */
     57     public ParameterUsageMarker()
     58     {
     59         this(false, false);
     60     }
     61 
     62 
     63     /**
     64      * Creates a new ParameterUsageMarker that optionally marks all parameters.
     65      * @param markThisParameter specifies whether all 'this' parameters should
     66      *                          be marked as being used.
     67      * @param markAllParameters specifies whether all other parameters should
     68      *                          be marked as being used.
     69      */
     70     public ParameterUsageMarker(boolean markThisParameter,
     71                                 boolean markAllParameters)
     72     {
     73         this.markThisParameter = markThisParameter;
     74         this.markAllParameters = markAllParameters;
     75     }
     76 
     77 
     78     // Implementations for MemberVisitor.
     79 
     80     public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
     81     {
     82         int parameterSize =
     83             ClassUtil.internalMethodParameterSize(programMethod.getDescriptor(programClass),
     84                                                   programMethod.getAccessFlags());
     85 
     86         if (parameterSize > 0)
     87         {
     88             int accessFlags = programMethod.getAccessFlags();
     89 
     90             // Must we mark the 'this' parameter?
     91             if (markThisParameter &&
     92                 (accessFlags & ClassConstants.ACC_STATIC) == 0)
     93             {
     94                 // Mark the 'this' parameter.
     95                 markParameterUsed(programMethod, 0);
     96             }
     97 
     98             // Must we mark all other parameters?
     99             if (markAllParameters)
    100             {
    101                 // Mark all parameters, without the 'this' parameter.
    102                 markUsedParameters(programMethod,
    103                                    (accessFlags & ClassConstants.ACC_STATIC) != 0 ?
    104                                        -1L : -2L);
    105             }
    106 
    107             // Is it a native method?
    108             if ((accessFlags & ClassConstants.ACC_NATIVE) != 0)
    109             {
    110                 // Mark all parameters.
    111                 markUsedParameters(programMethod, -1L);
    112             }
    113 
    114             // Is it an abstract method?
    115             else if ((accessFlags & ClassConstants.ACC_ABSTRACT) != 0)
    116             {
    117                 // Mark the 'this' parameter.
    118                 markParameterUsed(programMethod, 0);
    119             }
    120 
    121             // Is it a non-native, concrete method?
    122             else
    123             {
    124                 // Is the method not static, but synchronized, or can it have
    125                 // other implementations, or is it a class instance initializer?
    126                 if ((accessFlags & ClassConstants.ACC_STATIC) == 0 &&
    127                     ((accessFlags & ClassConstants.ACC_SYNCHRONIZED) != 0 ||
    128                      programClass.mayHaveImplementations(programMethod)            ||
    129                      programMethod.getName(programClass).equals(ClassConstants.METHOD_NAME_INIT)))
    130                 {
    131                     // Mark the 'this' parameter.
    132                     markParameterUsed(programMethod, 0);
    133                 }
    134 
    135                 // Mark the parameters that are used by the code.
    136                 programMethod.attributesAccept(programClass, this);
    137             }
    138 
    139             if (DEBUG)
    140             {
    141                 System.out.print("ParameterUsageMarker: ["+programClass.getName() +"."+programMethod.getName(programClass)+programMethod.getDescriptor(programClass)+"]: ");
    142                 for (int index = 0; index < parameterSize; index++)
    143                 {
    144                     System.out.print(isParameterUsed(programMethod, index) ? '+' : '-');
    145                 }
    146                 System.out.println();
    147             }
    148 
    149         }
    150 
    151         // Set the parameter size.
    152         setParameterSize(programMethod, parameterSize);
    153     }
    154 
    155 
    156     public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
    157     {
    158         // Can the method have other implementations?
    159         if (libraryClass.mayHaveImplementations(libraryMethod))
    160         {
    161             // All implementations must keep all parameters of this method,
    162             // including the 'this' parameter.
    163             markUsedParameters(libraryMethod, -1L);
    164         }
    165     }
    166 
    167 
    168     // Implementations for AttributeVisitor.
    169 
    170     public void visitAnyAttribute(Clazz clazz, Attribute attribute) {}
    171 
    172 
    173     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
    174     {
    175         // Evaluate the code.
    176         partialEvaluator.visitCodeAttribute(clazz, method, codeAttribute);
    177 
    178         // Mark the parameters that are used by the code.
    179         codeAttribute.instructionsAccept(clazz, method, this);
    180     }
    181 
    182 
    183     // Implementations for InstructionVisitor.
    184 
    185     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
    186 
    187 
    188     public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
    189     {
    190         if (partialEvaluator.isTraced(offset) &&
    191             variableInstruction.isLoad())
    192         {
    193             int parameterIndex = variableInstruction.variableIndex;
    194             if (parameterIndex < codeAttribute.u2maxLocals)
    195             {
    196                 Value producer =
    197                     partialEvaluator.getVariablesBefore(offset).getProducerValue(parameterIndex);
    198                 if (producer != null &&
    199                     producer.instructionOffsetValue().contains(PartialEvaluator.AT_METHOD_ENTRY))
    200                 {
    201                     // Mark the variable.
    202                     markParameterUsed(method, parameterIndex);
    203 
    204                     // Account for Category 2 instructions, which take up two entries.
    205                     if (variableInstruction.isCategory2())
    206                     {
    207                         markParameterUsed(method, parameterIndex + 1);
    208                     }
    209                 }
    210             }
    211         }
    212     }
    213 
    214 
    215     // Small utility methods.
    216 
    217     /**
    218      * Sets the total size of the parameters.
    219      */
    220     private static void setParameterSize(Method method, int parameterSize)
    221     {
    222         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
    223         if (info != null)
    224         {
    225             info.setParameterSize(parameterSize);
    226         }
    227     }
    228 
    229 
    230     /**
    231      * Returns the total size of the parameters.
    232      */
    233     public static int getParameterSize(Method method)
    234     {
    235         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
    236         return info != null ? info.getParameterSize() : 0;
    237     }
    238 
    239 
    240     /**
    241      * Marks the given parameter as being used.
    242      */
    243     public static void markParameterUsed(Method method, int variableIndex)
    244     {
    245         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
    246         if (info != null)
    247         {
    248             info.setParameterUsed(variableIndex);
    249         }
    250     }
    251 
    252 
    253     /**
    254      * Marks the given parameters as being used.
    255      */
    256     public static void markUsedParameters(Method method, long usedParameters)
    257     {
    258         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
    259         if (info != null)
    260         {
    261             info.setUsedParameters(info.getUsedParameters() | usedParameters);
    262         }
    263     }
    264 
    265 
    266     /**
    267      * Returns whether the given parameter is being used.
    268      */
    269     public static boolean isParameterUsed(Method method, int variableIndex)
    270     {
    271         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
    272         return info == null ||
    273                info.isParameterUsed(variableIndex);
    274     }
    275 
    276 
    277     /**
    278      * Returns which parameters are being used.
    279      */
    280     public static long getUsedParameters(Method method)
    281     {
    282         MethodOptimizationInfo info = MethodOptimizationInfo.getMethodOptimizationInfo(method);
    283         return info != null ? info.getUsedParameters() : -1L;
    284     }
    285 }
    286