Home | History | Annotate | Download | only in optimize
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2009 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.*;
     24 import proguard.classfile.*;
     25 import proguard.classfile.attribute.visitor.*;
     26 import proguard.classfile.constant.visitor.AllConstantVisitor;
     27 import proguard.classfile.editor.*;
     28 import proguard.classfile.instruction.visitor.*;
     29 import proguard.classfile.util.MethodLinker;
     30 import proguard.classfile.visitor.*;
     31 import proguard.evaluation.*;
     32 import proguard.evaluation.value.*;
     33 import proguard.optimize.evaluation.*;
     34 import proguard.optimize.info.*;
     35 import proguard.optimize.peephole.*;
     36 import proguard.util.*;
     37 
     38 import java.io.IOException;
     39 import java.util.*;
     40 
     41 /**
     42  * This class optimizes class pools according to a given configuration.
     43  *
     44  * @author Eric Lafortune
     45  */
     46 public class Optimizer
     47 {
     48     private static final String CLASS_MARKING_FINAL            = "class/marking/final";
     49     private static final String CLASS_MERGING_VERTICAL         = "class/merging/vertical";
     50     private static final String CLASS_MERGING_HORIZONTAL       = "class/merging/horizontal";
     51     private static final String FIELD_REMOVAL_WRITEONLY        = "field/removal/writeonly";
     52     private static final String FIELD_MARKING_PRIVATE          = "field/marking/private";
     53     private static final String FIELD_PROPAGATION_VALUE        = "field/propagation/value";
     54     private static final String METHOD_MARKING_PRIVATE         = "method/marking/private";
     55     private static final String METHOD_MARKING_STATIC          = "method/marking/static";
     56     private static final String METHOD_MARKING_FINAL           = "method/marking/final";
     57     private static final String METHOD_REMOVAL_PARAMETER       = "method/removal/parameter";
     58     private static final String METHOD_PROPAGATION_PARAMETER   = "method/propagation/parameter";
     59     private static final String METHOD_PROPAGATION_RETURNVALUE = "method/propagation/returnvalue";
     60     private static final String METHOD_INLINING_SHORT          = "method/inlining/short";
     61     private static final String METHOD_INLINING_UNIQUE         = "method/inlining/unique";
     62     private static final String METHOD_INLINING_TAILRECURSION  = "method/inlining/tailrecursion";
     63     private static final String CODE_MERGING                   = "code/merging";
     64     private static final String CODE_SIMPLIFICATION_VARIABLE   = "code/simplification/variable";
     65     private static final String CODE_SIMPLIFICATION_ARITHMETIC = "code/simplification/arithmetic";
     66     private static final String CODE_SIMPLIFICATION_CAST       = "code/simplification/cast";
     67     private static final String CODE_SIMPLIFICATION_FIELD      = "code/simplification/field";
     68     private static final String CODE_SIMPLIFICATION_BRANCH     = "code/simplification/branch";
     69     private static final String CODE_SIMPLIFICATION_ADVANCED   = "code/simplification/advanced";
     70     private static final String CODE_REMOVAL_ADVANCED          = "code/removal/advanced";
     71     private static final String CODE_REMOVAL_SIMPLE            = "code/removal/simple";
     72     private static final String CODE_REMOVAL_VARIABLE          = "code/removal/variable";
     73     private static final String CODE_REMOVAL_EXCEPTION         = "code/removal/exception";
     74     private static final String CODE_ALLOCATION_VARIABLE       = "code/allocation/variable";
     75 
     76 
     77     public static final String[] OPTIMIZATION_NAMES = new String[]
     78     {
     79         CLASS_MARKING_FINAL,
     80         CLASS_MERGING_VERTICAL,
     81         CLASS_MERGING_HORIZONTAL,
     82         FIELD_REMOVAL_WRITEONLY,
     83         FIELD_PROPAGATION_VALUE,
     84         METHOD_MARKING_PRIVATE,
     85         METHOD_MARKING_STATIC,
     86         METHOD_MARKING_FINAL,
     87         METHOD_REMOVAL_PARAMETER,
     88         METHOD_PROPAGATION_PARAMETER,
     89         METHOD_PROPAGATION_RETURNVALUE,
     90         METHOD_INLINING_SHORT,
     91         METHOD_INLINING_UNIQUE,
     92         METHOD_INLINING_TAILRECURSION,
     93         CODE_MERGING,
     94         CODE_SIMPLIFICATION_VARIABLE,
     95         CODE_SIMPLIFICATION_ARITHMETIC,
     96         CODE_SIMPLIFICATION_CAST,
     97         CODE_SIMPLIFICATION_FIELD,
     98         CODE_SIMPLIFICATION_BRANCH,
     99         CODE_SIMPLIFICATION_ADVANCED,
    100         CODE_REMOVAL_ADVANCED,
    101         CODE_REMOVAL_SIMPLE,
    102         CODE_REMOVAL_VARIABLE,
    103         CODE_REMOVAL_EXCEPTION,
    104         CODE_ALLOCATION_VARIABLE,
    105     };
    106 
    107 
    108     private final Configuration configuration;
    109 
    110 
    111     /**
    112      * Creates a new Optimizer.
    113      */
    114     public Optimizer(Configuration configuration)
    115     {
    116         this.configuration = configuration;
    117     }
    118 
    119 
    120     /**
    121      * Performs optimization of the given program class pool.
    122      */
    123     public boolean execute(ClassPool programClassPool,
    124                            ClassPool libraryClassPool) throws IOException
    125     {
    126         // Check if we have at least some keep commands.
    127         if (configuration.keep         == null &&
    128             configuration.applyMapping == null &&
    129             configuration.printMapping == null)
    130         {
    131             throw new IOException("You have to specify '-keep' options for the optimization step.");
    132         }
    133 
    134         // Create a matcher for filtering optimizations.
    135         StringMatcher filter = configuration.optimizations != null ?
    136             new ListParser(new NameParser()).parse(configuration.optimizations) :
    137             new ConstantMatcher(true);
    138 
    139         boolean classMarkingFinal            = filter.matches(CLASS_MARKING_FINAL);
    140         boolean classMergingVertical         = filter.matches(CLASS_MERGING_VERTICAL);
    141         boolean classMergingHorizontal       = filter.matches(CLASS_MERGING_HORIZONTAL);
    142         boolean fieldRemovalWriteonly        = filter.matches(FIELD_REMOVAL_WRITEONLY);
    143         boolean fieldMarkingPrivate          = filter.matches(FIELD_MARKING_PRIVATE);
    144         boolean fieldPropagationValue        = filter.matches(FIELD_PROPAGATION_VALUE);
    145         boolean methodMarkingPrivate         = filter.matches(METHOD_MARKING_PRIVATE);
    146         boolean methodMarkingStatic          = filter.matches(METHOD_MARKING_STATIC);
    147         boolean methodMarkingFinal           = filter.matches(METHOD_MARKING_FINAL);
    148         boolean methodRemovalParameter       = filter.matches(METHOD_REMOVAL_PARAMETER);
    149         boolean methodPropagationParameter   = filter.matches(METHOD_PROPAGATION_PARAMETER);
    150         boolean methodPropagationReturnvalue = filter.matches(METHOD_PROPAGATION_RETURNVALUE);
    151         boolean methodInliningShort          = filter.matches(METHOD_INLINING_SHORT);
    152         boolean methodInliningUnique         = filter.matches(METHOD_INLINING_UNIQUE);
    153         boolean methodInliningTailrecursion  = filter.matches(METHOD_INLINING_TAILRECURSION);
    154         boolean codeMerging                  = filter.matches(CODE_MERGING);
    155         boolean codeSimplificationVariable   = filter.matches(CODE_SIMPLIFICATION_VARIABLE);
    156         boolean codeSimplificationArithmetic = filter.matches(CODE_SIMPLIFICATION_ARITHMETIC);
    157         boolean codeSimplificationCast       = filter.matches(CODE_SIMPLIFICATION_CAST);
    158         boolean codeSimplificationField      = filter.matches(CODE_SIMPLIFICATION_FIELD);
    159         boolean codeSimplificationBranch     = filter.matches(CODE_SIMPLIFICATION_BRANCH);
    160         boolean codeSimplificationAdvanced   = filter.matches(CODE_SIMPLIFICATION_ADVANCED);
    161         boolean codeRemovalAdvanced          = filter.matches(CODE_REMOVAL_ADVANCED);
    162         boolean codeRemovalSimple            = filter.matches(CODE_REMOVAL_SIMPLE);
    163         boolean codeRemovalVariable          = filter.matches(CODE_REMOVAL_VARIABLE);
    164         boolean codeRemovalException         = filter.matches(CODE_REMOVAL_EXCEPTION);
    165         boolean codeAllocationVariable       = filter.matches(CODE_ALLOCATION_VARIABLE);
    166 
    167         // Create counters to count the numbers of optimizations.
    168         ClassCounter       classMarkingFinalCounter            = new ClassCounter();
    169         ClassCounter       classMergingVerticalCounter         = new ClassCounter();
    170         ClassCounter       classMergingHorizontalCounter       = new ClassCounter();
    171         MemberCounter      fieldRemovalWriteonlyCounter        = new MemberCounter();
    172         MemberCounter      fieldMarkingPrivateCounter          = new MemberCounter();
    173         MemberCounter      fieldPropagationValueCounter        = new MemberCounter();
    174         MemberCounter      methodMarkingPrivateCounter         = new MemberCounter();
    175         MemberCounter      methodMarkingStaticCounter          = new MemberCounter();
    176         MemberCounter      methodMarkingFinalCounter           = new MemberCounter();
    177         MemberCounter      methodRemovalParameterCounter       = new MemberCounter();
    178         MemberCounter      methodPropagationParameterCounter   = new MemberCounter();
    179         MemberCounter      methodPropagationReturnvalueCounter = new MemberCounter();
    180         InstructionCounter methodInliningShortCounter          = new InstructionCounter();
    181         InstructionCounter methodInliningUniqueCounter         = new InstructionCounter();
    182         InstructionCounter methodInliningTailrecursionCounter  = new InstructionCounter();
    183         InstructionCounter codeMergingCounter                  = new InstructionCounter();
    184         InstructionCounter codeSimplificationVariableCounter   = new InstructionCounter();
    185         InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter();
    186         InstructionCounter codeSimplificationCastCounter       = new InstructionCounter();
    187         InstructionCounter codeSimplificationFieldCounter      = new InstructionCounter();
    188         InstructionCounter codeSimplificationBranchCounter     = new InstructionCounter();
    189         InstructionCounter codeSimplificationAdvancedCounter   = new InstructionCounter();
    190         InstructionCounter deletedCounter                      = new InstructionCounter();
    191         InstructionCounter addedCounter                        = new InstructionCounter();
    192         MemberCounter      codeRemovalVariableCounter          = new MemberCounter();
    193         ExceptionCounter   codeRemovalExceptionCounter         = new ExceptionCounter();
    194         MemberCounter      codeAllocationVariableCounter       = new MemberCounter();
    195         MemberCounter      initializerFixCounter               = new MemberCounter();
    196 
    197         // Some optimizations are required by other optimizations.
    198         codeSimplificationAdvanced =
    199             codeSimplificationAdvanced ||
    200             fieldPropagationValue      ||
    201             methodPropagationParameter ||
    202             methodPropagationReturnvalue;
    203 
    204         codeRemovalAdvanced =
    205             codeRemovalAdvanced   ||
    206             fieldRemovalWriteonly ||
    207             methodMarkingStatic   ||
    208             methodRemovalParameter;
    209 
    210         codeRemovalSimple =
    211             codeRemovalSimple ||
    212             codeSimplificationBranch;
    213 
    214         codeRemovalException =
    215             codeRemovalException ||
    216             codeRemovalAdvanced ||
    217             codeRemovalSimple;
    218 
    219         // Clean up any old visitor info.
    220         programClassPool.classesAccept(new ClassCleaner());
    221         libraryClassPool.classesAccept(new ClassCleaner());
    222 
    223         // Link all methods that should get the same optimization info.
    224         programClassPool.classesAccept(new BottomClassFilter(
    225                                        new MethodLinker()));
    226         libraryClassPool.classesAccept(new BottomClassFilter(
    227                                        new MethodLinker()));
    228 
    229         // Create a visitor for marking the seeds.
    230         KeepMarker keepMarker = new KeepMarker();
    231         ClassPoolVisitor classPoolvisitor =
    232             ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
    233                                                                     keepMarker,
    234                                                                     keepMarker,
    235                                                                     false,
    236                                                                     true,
    237                                                                     false);
    238         // Mark the seeds.
    239         programClassPool.accept(classPoolvisitor);
    240         libraryClassPool.accept(classPoolvisitor);
    241 
    242         // All library classes and library class members remain unchanged.
    243         libraryClassPool.classesAccept(keepMarker);
    244         libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker));
    245 
    246         // We also keep all classes that are involved in .class constructs.
    247         programClassPool.classesAccept(
    248             new AllMethodVisitor(
    249             new AllAttributeVisitor(
    250             new AllInstructionVisitor(
    251             new DotClassClassVisitor(keepMarker)))));
    252 
    253         // We also keep all classes that are involved in Class.forName constructs.
    254         programClassPool.classesAccept(
    255             new AllConstantVisitor(
    256             new ClassForNameClassVisitor(keepMarker)));
    257 
    258         // Attach some optimization info to all classes and class members, so
    259         // it can be filled out later.
    260         programClassPool.classesAccept(new ClassOptimizationInfoSetter());
    261 
    262         programClassPool.classesAccept(new AllMemberVisitor(
    263                                        new MemberOptimizationInfoSetter()));
    264 
    265         if (configuration.assumeNoSideEffects != null)
    266         {
    267             // Create a visitor for marking methods that don't have any side effects.
    268             NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker();
    269             ClassPoolVisitor noClassPoolvisitor =
    270                 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects,
    271                                                                         null,
    272                                                                         noSideEffectMethodMarker);
    273 
    274             // Mark the seeds.
    275             programClassPool.accept(noClassPoolvisitor);
    276             libraryClassPool.accept(noClassPoolvisitor);
    277         }
    278 
    279         if (classMarkingFinal)
    280         {
    281             // Make classes final, whereever possible.
    282             programClassPool.classesAccept(
    283                 new ClassFinalizer(classMarkingFinalCounter));
    284         }
    285 
    286         if (methodMarkingFinal)
    287         {
    288             // Make methods final, whereever possible.
    289             programClassPool.classesAccept(
    290                 new AllMethodVisitor(
    291                 new MethodFinalizer(methodMarkingFinalCounter)));
    292         }
    293 
    294         if (fieldRemovalWriteonly)
    295         {
    296             // Mark all fields that are write-only.
    297             programClassPool.classesAccept(
    298                 new AllMethodVisitor(
    299                 new AllAttributeVisitor(
    300                 new AllInstructionVisitor(
    301                 new ReadWriteFieldMarker()))));
    302 
    303             // Count the write-only fields.
    304             programClassPool.classesAccept(
    305                 new AllFieldVisitor(
    306                 new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter)));
    307         }
    308         else
    309         {
    310             // Mark all fields as read/write.
    311             programClassPool.classesAccept(
    312                 new AllFieldVisitor(
    313                 new ReadWriteFieldMarker()));
    314         }
    315 
    316         // Mark all used parameters, including the 'this' parameters.
    317         programClassPool.classesAccept(
    318             new AllMethodVisitor(
    319             new OptimizationInfoMemberFilter(
    320             new ParameterUsageMarker(!methodMarkingStatic,
    321                                      !methodRemovalParameter))));
    322 
    323         // Mark all methods that have side effects.
    324         programClassPool.accept(new SideEffectMethodMarker());
    325 
    326 //        System.out.println("Optimizer.execute: before evaluation simplification");
    327 //        programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter()));
    328 
    329         // Perform partial evaluation for filling out fields, method parameters,
    330         // and method return values.
    331         ValueFactory valueFactory = new IdentifiedValueFactory();
    332 
    333         if (fieldPropagationValue      ||
    334             methodPropagationParameter ||
    335             methodPropagationReturnvalue)
    336         {
    337             // Fill out fields, method parameters, and return values, so they
    338             // can be propagated.
    339             InvocationUnit storingInvocationUnit =
    340                 new StoringInvocationUnit(valueFactory,
    341                                           fieldPropagationValue,
    342                                           methodPropagationParameter,
    343                                           methodPropagationReturnvalue);
    344 
    345             programClassPool.classesAccept(
    346                 new AllMethodVisitor(
    347                 new AllAttributeVisitor(
    348                 new PartialEvaluator(valueFactory, storingInvocationUnit, false))));
    349 
    350             // Count the constant fields and methods.
    351             programClassPool.classesAccept(
    352                 new MultiClassVisitor(
    353                 new ClassVisitor[]
    354                 {
    355                     new AllFieldVisitor(
    356                     new ConstantMemberFilter(fieldPropagationValueCounter)),
    357                     new AllMethodVisitor(
    358                     new ConstantParameterFilter(methodPropagationParameterCounter)),
    359                     new AllMethodVisitor(
    360                     new ConstantMemberFilter(methodPropagationReturnvalueCounter)),
    361                 }));
    362         }
    363 
    364         InvocationUnit loadingInvocationUnit =
    365             new LoadingInvocationUnit(valueFactory,
    366                                       fieldPropagationValue,
    367                                       methodPropagationParameter,
    368                                       methodPropagationReturnvalue);
    369 
    370         if (codeSimplificationAdvanced)
    371         {
    372             // Simplify based on partial evaluation, propagating constant
    373             // field values, method parameter values, and return values.
    374             programClassPool.classesAccept(
    375                 new AllMethodVisitor(
    376                 new AllAttributeVisitor(
    377                 new EvaluationSimplifier(
    378                 new PartialEvaluator(valueFactory, loadingInvocationUnit, false),
    379                 codeSimplificationAdvancedCounter))));
    380         }
    381 
    382         if (codeRemovalAdvanced)
    383         {
    384             // Remove code based on partial evaluation, also removing unused
    385             // parameters from method invocations, and making methods static
    386             // if possible.
    387             programClassPool.classesAccept(
    388                 new AllMethodVisitor(
    389                 new AllAttributeVisitor(
    390                 new EvaluationShrinker(
    391                 new PartialEvaluator(valueFactory, loadingInvocationUnit, !codeSimplificationAdvanced),
    392                 deletedCounter, addedCounter))));
    393         }
    394 
    395         if (methodRemovalParameter)
    396         {
    397             // Shrink the parameters in the method descriptors.
    398             programClassPool.classesAccept(
    399                 new AllMethodVisitor(
    400                 new OptimizationInfoMemberFilter(
    401                 new MethodDescriptorShrinker())));
    402         }
    403 
    404         if (methodMarkingStatic)
    405         {
    406             // Make all non-static methods that don't require the 'this'
    407             // parameter static.
    408             programClassPool.classesAccept(
    409                 new AllMethodVisitor(
    410                 new OptimizationInfoMemberFilter(
    411                 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC,
    412                 new MethodStaticizer(methodMarkingStaticCounter)))));
    413         }
    414 
    415         if (methodRemovalParameter)
    416         {
    417             // Fix all references to class members.
    418             // This operation also updates the stack sizes.
    419             programClassPool.classesAccept(
    420                 new MemberReferenceFixer());
    421         }
    422 
    423         if (methodRemovalParameter ||
    424             methodMarkingPrivate   ||
    425             methodMarkingStatic)
    426         {
    427             // Remove all unused parameters from the byte code, shifting all
    428             // remaining variables.
    429             // This operation also updates the local variable frame sizes.
    430             programClassPool.classesAccept(
    431                 new AllMethodVisitor(
    432                 new AllAttributeVisitor(
    433                 new ParameterShrinker(methodRemovalParameterCounter))));
    434         }
    435         else if (codeRemovalAdvanced)
    436         {
    437             // Just update the local variable frame sizes.
    438             programClassPool.classesAccept(
    439                 new AllMethodVisitor(
    440                 new AllAttributeVisitor(
    441                 new StackSizeUpdater())));
    442         }
    443 
    444 //        // Specializing the class member descriptors seems to increase the
    445 //        // class file size, on average.
    446 //        // Specialize all class member descriptors.
    447 //        programClassPool.classesAccept(new AllMemberVisitor(
    448 //                                       new OptimizationInfoMemberFilter(
    449 //                                       new MemberDescriptorSpecializer())));
    450 //
    451 //        // Fix all references to classes, for MemberDescriptorSpecializer.
    452 //        programClassPool.classesAccept(new AllMemberVisitor(
    453 //                                       new OptimizationInfoMemberFilter(
    454 //                                       new ClassReferenceFixer(true))));
    455 
    456         // Mark all classes with package visible members.
    457         // Mark all exception catches of methods.
    458         // Count all method invocations.
    459         // Mark super invocations and other access of methods.
    460         programClassPool.classesAccept(
    461             new MultiClassVisitor(
    462             new ClassVisitor[]
    463             {
    464                 new AllConstantVisitor(
    465                 new PackageVisibleMemberInvokingClassMarker()),
    466                 new AllMethodVisitor(
    467                 new MultiMemberVisitor(
    468                 new MemberVisitor[]
    469                 {
    470                     new PackageVisibleMemberContainingClassMarker(),
    471                     new AllAttributeVisitor(
    472                     new MultiAttributeVisitor(
    473                     new AttributeVisitor[]
    474                     {
    475                         new CatchExceptionMarker(),
    476                         new AllInstructionVisitor(
    477                         new MultiInstructionVisitor(
    478                         new InstructionVisitor[]
    479                         {
    480                             new InstantiationClassMarker(),
    481                             new InstanceofClassMarker(),
    482                             new DotClassMarker(),
    483                             new MethodInvocationMarker(),
    484                             new SuperInvocationMarker(),
    485                             new BackwardBranchMarker(),
    486                             new AccessMethodMarker(),
    487                         })),
    488                         new AllExceptionInfoVisitor(
    489                         new ExceptionHandlerConstantVisitor(
    490                         new ReferencedClassVisitor(
    491                         new CaughtClassMarker()))),
    492                     })),
    493                 })),
    494             }));
    495 
    496         if (classMergingVertical)
    497         {
    498             // Merge classes into their superclasses or interfaces.
    499             programClassPool.classesAccept(
    500                 new VerticalClassMerger(configuration.allowAccessModification,
    501                                         configuration.mergeInterfacesAggressively,
    502                                         classMergingVerticalCounter));
    503         }
    504 
    505         if (classMergingHorizontal)
    506         {
    507             // Merge classes into their sibling classes.
    508             programClassPool.classesAccept(
    509                 new HorizontalClassMerger(configuration.allowAccessModification,
    510                                           configuration.mergeInterfacesAggressively,
    511                                           classMergingHorizontalCounter));
    512         }
    513 
    514         if (classMergingVertical ||
    515             classMergingHorizontal)
    516         {
    517             // Clean up inner class attributes to avoid loops.
    518             programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover());
    519 
    520             // Update references to merged classes.
    521             programClassPool.classesAccept(new TargetClassChanger());
    522             programClassPool.classesAccept(new ClassReferenceFixer(true));
    523             programClassPool.classesAccept(new MemberReferenceFixer());
    524 
    525             if (configuration.allowAccessModification)
    526             {
    527                 // Fix the access flags of referenced merged classes and their
    528                 // class members.
    529                 programClassPool.classesAccept(
    530                     new AllConstantVisitor(
    531                     new AccessFixer()));
    532             }
    533         }
    534 
    535         if (methodRemovalParameter ||
    536             classMergingVertical   ||
    537             classMergingHorizontal)
    538         {
    539             // Tweak the descriptors of duplicate initializers.
    540             programClassPool.classesAccept(
    541                 new AllMethodVisitor(
    542                 new DuplicateInitializerFixer(initializerFixCounter)));
    543 
    544             if (initializerFixCounter.getCount() > 0)
    545             {
    546                 // Fix all invocations of tweaked initializers.
    547                 programClassPool.classesAccept(
    548                     new AllMethodVisitor(
    549                     new AllAttributeVisitor(
    550                     new DuplicateInitializerInvocationFixer(addedCounter))));
    551 
    552                 // Fix all references to tweaked initializers.
    553                 programClassPool.classesAccept(new MemberReferenceFixer());
    554             }
    555         }
    556 
    557         if (methodInliningUnique)
    558         {
    559             // Inline methods that are only invoked once.
    560             programClassPool.classesAccept(
    561                 new AllMethodVisitor(
    562                 new AllAttributeVisitor(
    563                 new MethodInliner(configuration.microEdition,
    564                                   configuration.allowAccessModification,
    565                                   true,
    566                                   methodInliningUniqueCounter))));
    567         }
    568 
    569         if (methodInliningShort)
    570         {
    571             // Inline short methods.
    572             programClassPool.classesAccept(
    573                 new AllMethodVisitor(
    574                 new AllAttributeVisitor(
    575                 new MethodInliner(configuration.microEdition,
    576                                   configuration.allowAccessModification,
    577                                   false,
    578                                   methodInliningShortCounter))));
    579         }
    580 
    581         if (methodInliningTailrecursion)
    582         {
    583             // Simplify tail recursion calls.
    584             programClassPool.classesAccept(
    585                 new AllMethodVisitor(
    586                 new AllAttributeVisitor(
    587                 new TailRecursionSimplifier(methodInliningTailrecursionCounter))));
    588         }
    589 
    590         if (fieldMarkingPrivate ||
    591             methodMarkingPrivate)
    592         {
    593             // Mark all class members that can not be made private.
    594             programClassPool.classesAccept(
    595                 new NonPrivateMemberMarker());
    596         }
    597 
    598         if (fieldMarkingPrivate ||
    599             methodMarkingPrivate)
    600         {
    601             // Make all non-private fields private, whereever possible.
    602             programClassPool.classesAccept(
    603                 new AllFieldVisitor(
    604                 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
    605                 new MemberPrivatizer(fieldMarkingPrivateCounter))));
    606         }
    607 
    608         if (methodMarkingPrivate)
    609         {
    610             // Make all non-private methods private, whereever possible.
    611             programClassPool.classesAccept(
    612                 new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE,
    613                 new AllMethodVisitor(
    614                 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
    615                 new MemberPrivatizer(methodMarkingPrivateCounter)))));
    616         }
    617 
    618         if ((methodInliningUnique ||
    619              methodInliningShort  ||
    620              methodInliningTailrecursion) &&
    621             configuration.allowAccessModification)
    622         {
    623             // Fix the access flags of referenced classes and class members,
    624             // for MethodInliner.
    625             programClassPool.classesAccept(
    626                 new AllConstantVisitor(
    627                 new AccessFixer()));
    628         }
    629 
    630         if (methodRemovalParameter ||
    631             classMergingVertical   ||
    632             classMergingHorizontal ||
    633             methodMarkingPrivate)
    634         {
    635             // Fix invocations of interface methods, of methods that have become
    636             // non-abstract or private, and of methods that have moved to a
    637             // different package.
    638             programClassPool.classesAccept(
    639                 new AllMemberVisitor(
    640                 new AllAttributeVisitor(
    641                 new MethodInvocationFixer())));
    642         }
    643 
    644         if (codeMerging)
    645         {
    646             // Share common blocks of code at branches.
    647             programClassPool.classesAccept(
    648                 new AllMethodVisitor(
    649                 new AllAttributeVisitor(
    650                 new GotoCommonCodeReplacer(codeMergingCounter))));
    651         }
    652 
    653         // Create a branch target marker and a code attribute editor that can
    654         // be reused for all code attributes.
    655         BranchTargetFinder  branchTargetFinder  = new BranchTargetFinder();
    656         CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
    657 
    658         List peepholeOptimizations = new ArrayList();
    659         if (codeSimplificationVariable)
    660         {
    661             // Peephole optimizations involving local variables.
    662             peepholeOptimizations.add(
    663                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    664                                                  InstructionSequenceConstants.VARIABLE,
    665                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter));
    666         }
    667 
    668         if (codeSimplificationArithmetic)
    669         {
    670             // Peephole optimizations involving arithmetic operations.
    671             peepholeOptimizations.add(
    672                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    673                                                  InstructionSequenceConstants.ARITHMETIC,
    674                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter));
    675         }
    676 
    677         if (codeSimplificationCast)
    678         {
    679             // Peephole optimizations involving cast operations.
    680             peepholeOptimizations.add(
    681                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    682                                                  InstructionSequenceConstants.CAST,
    683                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter));
    684         }
    685 
    686         if (codeSimplificationField)
    687         {
    688             // Peephole optimizations involving fields.
    689             peepholeOptimizations.add(
    690                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    691                                                  InstructionSequenceConstants.FIELD,
    692                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter));
    693         }
    694 
    695         if (codeSimplificationBranch)
    696         {
    697             // Peephole optimizations involving branches.
    698             peepholeOptimizations.add(
    699                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    700                                                  InstructionSequenceConstants.BRANCH,
    701                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter));
    702 
    703             // Include optimization of branches to branches and returns.
    704             peepholeOptimizations.add(
    705                 new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter));
    706             peepholeOptimizations.add(
    707                 new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter));
    708         }
    709 
    710         if (!peepholeOptimizations.isEmpty())
    711         {
    712             // Convert the list into an array.
    713             InstructionVisitor[] peepholeOptimizationsArray =
    714                 new InstructionVisitor[peepholeOptimizations.size()];
    715             peepholeOptimizations.toArray(peepholeOptimizationsArray);
    716 
    717             // Perform the peephole optimisations.
    718             programClassPool.classesAccept(
    719                 new AllMethodVisitor(
    720                 new AllAttributeVisitor(
    721                 new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor,
    722                 new MultiInstructionVisitor(
    723                 peepholeOptimizationsArray)))));
    724         }
    725 
    726         if (codeRemovalException)
    727         {
    728             // Remove unnecessary exception handlers.
    729             programClassPool.classesAccept(
    730                 new AllMethodVisitor(
    731                 new AllAttributeVisitor(
    732                 new UnreachableExceptionRemover(codeRemovalExceptionCounter))));
    733         }
    734 
    735         if (codeRemovalSimple)
    736         {
    737             // Remove unreachable code.
    738             programClassPool.classesAccept(
    739                 new AllMethodVisitor(
    740                 new AllAttributeVisitor(
    741                 new UnreachableCodeRemover(deletedCounter))));
    742         }
    743 
    744         if (codeRemovalVariable)
    745         {
    746             // Remove all unused local variables.
    747             programClassPool.classesAccept(
    748                 new AllMethodVisitor(
    749                 new AllAttributeVisitor(
    750                 new VariableShrinker(codeRemovalVariableCounter))));
    751         }
    752         else
    753         {
    754             // Clean up all unused local variables.
    755             programClassPool.classesAccept(
    756                 new AllMethodVisitor(
    757                 new AllAttributeVisitor(
    758                 new VariableCleaner())));
    759         }
    760 
    761         if (codeAllocationVariable)
    762         {
    763             // Optimize the variables.
    764             programClassPool.classesAccept(
    765                 new AllMethodVisitor(
    766                 new AllAttributeVisitor(
    767                 new VariableOptimizer(false, codeAllocationVariableCounter))));
    768         }
    769 
    770         int classMarkingFinalCount            = classMarkingFinalCounter           .getCount();
    771         int classMergingVerticalCount         = classMergingVerticalCounter        .getCount();
    772         int classMergingHorizontalCount       = classMergingHorizontalCounter      .getCount();
    773         int fieldRemovalWriteonlyCount        = fieldRemovalWriteonlyCounter       .getCount();
    774         int fieldMarkingPrivateCount          = fieldMarkingPrivateCounter         .getCount();
    775         int fieldPropagationValueCount        = fieldPropagationValueCounter       .getCount();
    776         int methodMarkingPrivateCount         = methodMarkingPrivateCounter        .getCount();
    777         int methodMarkingStaticCount          = methodMarkingStaticCounter         .getCount();
    778         int methodMarkingFinalCount           = methodMarkingFinalCounter          .getCount();
    779         int methodRemovalParameterCount       = methodRemovalParameterCounter      .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter.getCount();
    780         int methodPropagationParameterCount   = methodPropagationParameterCounter  .getCount();
    781         int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount();
    782         int methodInliningShortCount          = methodInliningShortCounter         .getCount();
    783         int methodInliningUniqueCount         = methodInliningUniqueCounter        .getCount();
    784         int methodInliningTailrecursionCount  = methodInliningTailrecursionCounter .getCount();
    785         int codeMergingCount                  = codeMergingCounter                 .getCount();
    786         int codeSimplificationVariableCount   = codeSimplificationVariableCounter  .getCount();
    787         int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter.getCount();
    788         int codeSimplificationCastCount       = codeSimplificationCastCounter      .getCount();
    789         int codeSimplificationFieldCount      = codeSimplificationFieldCounter     .getCount();
    790         int codeSimplificationBranchCount     = codeSimplificationBranchCounter    .getCount();
    791         int codeSimplificationAdvancedCount   = codeSimplificationAdvancedCounter  .getCount();
    792         int codeRemovalCount                  = deletedCounter                     .getCount() - addedCounter.getCount();
    793         int codeRemovalVariableCount          = codeRemovalVariableCounter         .getCount();
    794         int codeRemovalExceptionCount         = codeRemovalExceptionCounter        .getCount();
    795         int codeAllocationVariableCount       = codeAllocationVariableCounter      .getCount();
    796 
    797         if (configuration.verbose)
    798         {
    799             System.out.println("  Number of finalized classes:                 " + classMarkingFinalCount            + disabled(classMarkingFinal));
    800             System.out.println("  Number of vertically merged classes:         " + classMergingVerticalCount         + disabled(classMergingVertical));
    801             System.out.println("  Number of horizontally merged classes:       " + classMergingHorizontalCount       + disabled(classMergingHorizontal));
    802             System.out.println("  Number of removed write-only fields:         " + fieldRemovalWriteonlyCount        + disabled(fieldRemovalWriteonly));
    803             System.out.println("  Number of privatized fields:                 " + fieldMarkingPrivateCount          + disabled(fieldMarkingPrivate));
    804             System.out.println("  Number of inlined constant fields:           " + fieldPropagationValueCount        + disabled(fieldPropagationValue));
    805             System.out.println("  Number of privatized methods:                " + methodMarkingPrivateCount         + disabled(methodMarkingPrivate));
    806             System.out.println("  Number of staticized methods:                " + methodMarkingStaticCount          + disabled(methodMarkingStatic));
    807             System.out.println("  Number of finalized methods:                 " + methodMarkingFinalCount           + disabled(methodMarkingFinal));
    808             System.out.println("  Number of removed method parameters:         " + methodRemovalParameterCount       + disabled(methodRemovalParameter));
    809             System.out.println("  Number of inlined constant parameters:       " + methodPropagationParameterCount   + disabled(methodPropagationParameter));
    810             System.out.println("  Number of inlined constant return values:    " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue));
    811             System.out.println("  Number of inlined short method calls:        " + methodInliningShortCount          + disabled(methodInliningShort));
    812             System.out.println("  Number of inlined unique method calls:       " + methodInliningUniqueCount         + disabled(methodInliningUnique));
    813             System.out.println("  Number of inlined tail recursion calls:      " + methodInliningTailrecursionCount  + disabled(methodInliningTailrecursion));
    814             System.out.println("  Number of merged code blocks:                " + codeMergingCount                  + disabled(codeMerging));
    815             System.out.println("  Number of variable peephole optimizations:   " + codeSimplificationVariableCount   + disabled(codeSimplificationVariable));
    816             System.out.println("  Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic));
    817             System.out.println("  Number of cast peephole optimizations:       " + codeSimplificationCastCount       + disabled(codeSimplificationCast));
    818             System.out.println("  Number of field peephole optimizations:      " + codeSimplificationFieldCount      + disabled(codeSimplificationField));
    819             System.out.println("  Number of branch peephole optimizations:     " + codeSimplificationBranchCount     + disabled(codeSimplificationBranch));
    820             System.out.println("  Number of simplified instructions:           " + codeSimplificationAdvancedCount   + disabled(codeSimplificationAdvanced));
    821             System.out.println("  Number of removed instructions:              " + codeRemovalCount                  + disabled(codeRemovalAdvanced));
    822             System.out.println("  Number of removed local variables:           " + codeRemovalVariableCount          + disabled(codeRemovalVariable));
    823             System.out.println("  Number of removed exception blocks:          " + codeRemovalExceptionCount         + disabled(codeRemovalException));
    824             System.out.println("  Number of optimized local variable frames:   " + codeAllocationVariableCount       + disabled(codeAllocationVariable));
    825         }
    826 
    827         return classMarkingFinalCount            > 0 ||
    828                classMergingVerticalCount         > 0 ||
    829                classMergingHorizontalCount       > 0 ||
    830                fieldRemovalWriteonlyCount        > 0 ||
    831                fieldMarkingPrivateCount          > 0 ||
    832                methodMarkingPrivateCount         > 0 ||
    833                methodMarkingStaticCount          > 0 ||
    834                methodMarkingFinalCount           > 0 ||
    835                fieldPropagationValueCount        > 0 ||
    836                methodRemovalParameterCount       > 0 ||
    837                methodPropagationParameterCount   > 0 ||
    838                methodPropagationReturnvalueCount > 0 ||
    839                methodInliningShortCount          > 0 ||
    840                methodInliningUniqueCount         > 0 ||
    841                methodInliningTailrecursionCount  > 0 ||
    842                codeMergingCount                  > 0 ||
    843                codeSimplificationVariableCount   > 0 ||
    844                codeSimplificationArithmeticCount > 0 ||
    845                codeSimplificationCastCount       > 0 ||
    846                codeSimplificationFieldCount      > 0 ||
    847                codeSimplificationBranchCount     > 0 ||
    848                codeSimplificationAdvancedCount   > 0 ||
    849                codeRemovalCount                  > 0 ||
    850                codeRemovalVariableCount          > 0 ||
    851                codeRemovalExceptionCount         > 0 ||
    852                codeAllocationVariableCount       > 0;
    853     }
    854 
    855 
    856     /**
    857      * Returns a String indicating whether the given flag is enabled or
    858      * disabled.
    859      */
    860     private String disabled(boolean flag)
    861     {
    862         return flag ? "" : "   (disabled)";
    863     }
    864 
    865 
    866     /**
    867      * Returns a String indicating whether the given flags are enabled or
    868      * disabled.
    869      */
    870     private String disabled(boolean flag1, boolean flag2)
    871     {
    872         return flag1 && flag2 ? "" :
    873                flag1 || flag2 ? "   (partially disabled)" :
    874                                 "   (disabled)";
    875     }
    876 }
    877