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.*;
     24 import proguard.classfile.*;
     25 import proguard.classfile.attribute.visitor.*;
     26 import proguard.classfile.constant.visitor.*;
     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.InvocationUnit;
     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_UNBOXING_ENUM            = "class/unboxing/enum";
     50     private static final String CLASS_MERGING_VERTICAL         = "class/merging/vertical";
     51     private static final String CLASS_MERGING_HORIZONTAL       = "class/merging/horizontal";
     52     private static final String FIELD_REMOVAL_WRITEONLY        = "field/removal/writeonly";
     53     private static final String FIELD_MARKING_PRIVATE          = "field/marking/private";
     54     private static final String FIELD_PROPAGATION_VALUE        = "field/propagation/value";
     55     private static final String METHOD_MARKING_PRIVATE         = "method/marking/private";
     56     private static final String METHOD_MARKING_STATIC          = "method/marking/static";
     57     private static final String METHOD_MARKING_FINAL           = "method/marking/final";
     58     private static final String METHOD_REMOVAL_PARAMETER       = "method/removal/parameter";
     59     private static final String METHOD_PROPAGATION_PARAMETER   = "method/propagation/parameter";
     60     private static final String METHOD_PROPAGATION_RETURNVALUE = "method/propagation/returnvalue";
     61     private static final String METHOD_INLINING_SHORT          = "method/inlining/short";
     62     private static final String METHOD_INLINING_UNIQUE         = "method/inlining/unique";
     63     private static final String METHOD_INLINING_TAILRECURSION  = "method/inlining/tailrecursion";
     64     private static final String CODE_MERGING                   = "code/merging";
     65     private static final String CODE_SIMPLIFICATION_VARIABLE   = "code/simplification/variable";
     66     private static final String CODE_SIMPLIFICATION_ARITHMETIC = "code/simplification/arithmetic";
     67     private static final String CODE_SIMPLIFICATION_CAST       = "code/simplification/cast";
     68     private static final String CODE_SIMPLIFICATION_FIELD      = "code/simplification/field";
     69     private static final String CODE_SIMPLIFICATION_BRANCH     = "code/simplification/branch";
     70     private static final String CODE_SIMPLIFICATION_STRING     = "code/simplification/string";
     71     private static final String CODE_SIMPLIFICATION_ADVANCED   = "code/simplification/advanced";
     72     private static final String CODE_REMOVAL_ADVANCED          = "code/removal/advanced";
     73     private static final String CODE_REMOVAL_SIMPLE            = "code/removal/simple";
     74     private static final String CODE_REMOVAL_VARIABLE          = "code/removal/variable";
     75     private static final String CODE_REMOVAL_EXCEPTION         = "code/removal/exception";
     76     private static final String CODE_ALLOCATION_VARIABLE       = "code/allocation/variable";
     77 
     78 
     79     public static final String[] OPTIMIZATION_NAMES = new String[]
     80     {
     81         CLASS_MARKING_FINAL,
     82         CLASS_MERGING_VERTICAL,
     83         CLASS_MERGING_HORIZONTAL,
     84         FIELD_REMOVAL_WRITEONLY,
     85         FIELD_MARKING_PRIVATE,
     86         FIELD_PROPAGATION_VALUE,
     87         METHOD_MARKING_PRIVATE,
     88         METHOD_MARKING_STATIC,
     89         METHOD_MARKING_FINAL,
     90         METHOD_REMOVAL_PARAMETER,
     91         METHOD_PROPAGATION_PARAMETER,
     92         METHOD_PROPAGATION_RETURNVALUE,
     93         METHOD_INLINING_SHORT,
     94         METHOD_INLINING_UNIQUE,
     95         METHOD_INLINING_TAILRECURSION,
     96         CODE_MERGING,
     97         CODE_SIMPLIFICATION_VARIABLE,
     98         CODE_SIMPLIFICATION_ARITHMETIC,
     99         CODE_SIMPLIFICATION_CAST,
    100         CODE_SIMPLIFICATION_FIELD,
    101         CODE_SIMPLIFICATION_BRANCH,
    102         CODE_SIMPLIFICATION_STRING,
    103         CODE_SIMPLIFICATION_ADVANCED,
    104         CODE_REMOVAL_ADVANCED,
    105         CODE_REMOVAL_SIMPLE,
    106         CODE_REMOVAL_VARIABLE,
    107         CODE_REMOVAL_EXCEPTION,
    108         CODE_ALLOCATION_VARIABLE,
    109     };
    110 
    111 
    112     private final Configuration configuration;
    113 
    114 
    115     /**
    116      * Creates a new Optimizer.
    117      */
    118     public Optimizer(Configuration configuration)
    119     {
    120         this.configuration = configuration;
    121     }
    122 
    123 
    124     /**
    125      * Performs optimization of the given program class pool.
    126      */
    127     public boolean execute(ClassPool programClassPool,
    128                            ClassPool libraryClassPool) throws IOException
    129     {
    130         // Check if we have at least some keep commands.
    131         if (configuration.keep         == null &&
    132             configuration.applyMapping == null &&
    133             configuration.printMapping == null)
    134         {
    135             throw new IOException("You have to specify '-keep' options for the optimization step.");
    136         }
    137 
    138         // Create a matcher for filtering optimizations.
    139         StringMatcher filter = configuration.optimizations != null ?
    140             new ListParser(new NameParser()).parse(configuration.optimizations) :
    141             new ConstantMatcher(true);
    142 
    143         boolean classMarkingFinal            = filter.matches(CLASS_MARKING_FINAL);
    144         boolean classUnboxingEnum            = filter.matches(CLASS_UNBOXING_ENUM);
    145         boolean classMergingVertical         = filter.matches(CLASS_MERGING_VERTICAL);
    146         boolean classMergingHorizontal       = filter.matches(CLASS_MERGING_HORIZONTAL);
    147         boolean fieldRemovalWriteonly        = filter.matches(FIELD_REMOVAL_WRITEONLY);
    148         boolean fieldMarkingPrivate          = filter.matches(FIELD_MARKING_PRIVATE);
    149         boolean fieldPropagationValue        = filter.matches(FIELD_PROPAGATION_VALUE);
    150         boolean methodMarkingPrivate         = filter.matches(METHOD_MARKING_PRIVATE);
    151         boolean methodMarkingStatic          = filter.matches(METHOD_MARKING_STATIC);
    152         boolean methodMarkingFinal           = filter.matches(METHOD_MARKING_FINAL);
    153         boolean methodRemovalParameter       = filter.matches(METHOD_REMOVAL_PARAMETER);
    154         boolean methodPropagationParameter   = filter.matches(METHOD_PROPAGATION_PARAMETER);
    155         boolean methodPropagationReturnvalue = filter.matches(METHOD_PROPAGATION_RETURNVALUE);
    156         boolean methodInliningShort          = filter.matches(METHOD_INLINING_SHORT);
    157         boolean methodInliningUnique         = filter.matches(METHOD_INLINING_UNIQUE);
    158         boolean methodInliningTailrecursion  = filter.matches(METHOD_INLINING_TAILRECURSION);
    159         boolean codeMerging                  = filter.matches(CODE_MERGING);
    160         boolean codeSimplificationVariable   = filter.matches(CODE_SIMPLIFICATION_VARIABLE);
    161         boolean codeSimplificationArithmetic = filter.matches(CODE_SIMPLIFICATION_ARITHMETIC);
    162         boolean codeSimplificationCast       = filter.matches(CODE_SIMPLIFICATION_CAST);
    163         boolean codeSimplificationField      = filter.matches(CODE_SIMPLIFICATION_FIELD);
    164         boolean codeSimplificationBranch     = filter.matches(CODE_SIMPLIFICATION_BRANCH);
    165         boolean codeSimplificationString     = filter.matches(CODE_SIMPLIFICATION_STRING);
    166         boolean codeSimplificationAdvanced   = filter.matches(CODE_SIMPLIFICATION_ADVANCED);
    167         boolean codeRemovalAdvanced          = filter.matches(CODE_REMOVAL_ADVANCED);
    168         boolean codeRemovalSimple            = filter.matches(CODE_REMOVAL_SIMPLE);
    169         boolean codeRemovalVariable          = filter.matches(CODE_REMOVAL_VARIABLE);
    170         boolean codeRemovalException         = filter.matches(CODE_REMOVAL_EXCEPTION);
    171         boolean codeAllocationVariable       = filter.matches(CODE_ALLOCATION_VARIABLE);
    172 
    173         // Create counters to count the numbers of optimizations.
    174         ClassCounter       classMarkingFinalCounter            = new ClassCounter();
    175         ClassCounter       classUnboxingEnumCounter            = new ClassCounter();
    176         ClassCounter       classMergingVerticalCounter         = new ClassCounter();
    177         ClassCounter       classMergingHorizontalCounter       = new ClassCounter();
    178         MemberCounter      fieldRemovalWriteonlyCounter        = new MemberCounter();
    179         MemberCounter      fieldMarkingPrivateCounter          = new MemberCounter();
    180         MemberCounter      fieldPropagationValueCounter        = new MemberCounter();
    181         MemberCounter      methodMarkingPrivateCounter         = new MemberCounter();
    182         MemberCounter      methodMarkingStaticCounter          = new MemberCounter();
    183         MemberCounter      methodMarkingFinalCounter           = new MemberCounter();
    184         MemberCounter      methodRemovalParameterCounter       = new MemberCounter();
    185         MemberCounter      methodPropagationParameterCounter   = new MemberCounter();
    186         MemberCounter      methodPropagationReturnvalueCounter = new MemberCounter();
    187         InstructionCounter methodInliningShortCounter          = new InstructionCounter();
    188         InstructionCounter methodInliningUniqueCounter         = new InstructionCounter();
    189         InstructionCounter methodInliningTailrecursionCounter  = new InstructionCounter();
    190         InstructionCounter codeMergingCounter                  = new InstructionCounter();
    191         InstructionCounter codeSimplificationVariableCounter   = new InstructionCounter();
    192         InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter();
    193         InstructionCounter codeSimplificationCastCounter       = new InstructionCounter();
    194         InstructionCounter codeSimplificationFieldCounter      = new InstructionCounter();
    195         InstructionCounter codeSimplificationBranchCounter     = new InstructionCounter();
    196         InstructionCounter codeSimplificationStringCounter     = new InstructionCounter();
    197         InstructionCounter codeSimplificationAdvancedCounter   = new InstructionCounter();
    198         InstructionCounter deletedCounter                      = new InstructionCounter();
    199         InstructionCounter addedCounter                        = new InstructionCounter();
    200         MemberCounter      codeRemovalVariableCounter          = new MemberCounter();
    201         ExceptionCounter   codeRemovalExceptionCounter         = new ExceptionCounter();
    202         MemberCounter      codeAllocationVariableCounter       = new MemberCounter();
    203         MemberCounter      initializerFixCounter1              = new MemberCounter();
    204         MemberCounter      initializerFixCounter2              = new MemberCounter();
    205 
    206         // Some optimizations are required by other optimizations.
    207         codeSimplificationAdvanced =
    208             codeSimplificationAdvanced ||
    209             fieldPropagationValue      ||
    210             methodPropagationParameter ||
    211             methodPropagationReturnvalue;
    212 
    213         codeRemovalAdvanced =
    214             codeRemovalAdvanced   ||
    215             fieldRemovalWriteonly ||
    216             methodMarkingStatic   ||
    217             methodRemovalParameter;
    218 
    219         codeRemovalSimple =
    220             codeRemovalSimple ||
    221             codeSimplificationBranch;
    222 
    223         codeRemovalException =
    224             codeRemovalException ||
    225             codeRemovalAdvanced ||
    226             codeRemovalSimple;
    227 
    228         // Clean up any old visitor info.
    229         programClassPool.classesAccept(new ClassCleaner());
    230         libraryClassPool.classesAccept(new ClassCleaner());
    231 
    232         // Link all methods that should get the same optimization info.
    233         programClassPool.classesAccept(new BottomClassFilter(
    234                                        new MethodLinker()));
    235         libraryClassPool.classesAccept(new BottomClassFilter(
    236                                        new MethodLinker()));
    237 
    238         // Create a visitor for marking the seeds.
    239         KeepMarker keepMarker = new KeepMarker();
    240         ClassPoolVisitor classPoolvisitor =
    241             ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
    242                                                                     keepMarker,
    243                                                                     keepMarker,
    244                                                                     false,
    245                                                                     true,
    246                                                                     false);
    247         // Mark the seeds.
    248         programClassPool.accept(classPoolvisitor);
    249         libraryClassPool.accept(classPoolvisitor);
    250 
    251         // All library classes and library class members remain unchanged.
    252         libraryClassPool.classesAccept(keepMarker);
    253         libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker));
    254 
    255         // We also keep all classes that are involved in .class constructs.
    256         // We're not looking at enum classes though, so they can be simplified.
    257         programClassPool.classesAccept(
    258             new ClassAccessFilter(0, ClassConstants.ACC_ENUM,
    259             new AllMethodVisitor(
    260             new AllAttributeVisitor(
    261             new AllInstructionVisitor(
    262             new DotClassClassVisitor(keepMarker))))));
    263 
    264         // We also keep all classes that are accessed dynamically.
    265         programClassPool.classesAccept(
    266             new AllConstantVisitor(
    267             new ConstantTagFilter(ClassConstants.CONSTANT_String,
    268             new ReferencedClassVisitor(keepMarker))));
    269 
    270         // We also keep all class members that are accessed dynamically.
    271         programClassPool.classesAccept(
    272             new AllConstantVisitor(
    273             new ConstantTagFilter(ClassConstants.CONSTANT_String,
    274             new ReferencedMemberVisitor(keepMarker))));
    275 
    276         // We also keep all bootstrap method signatures.
    277         programClassPool.classesAccept(
    278             new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
    279             new AllAttributeVisitor(
    280             new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
    281             new AllBootstrapMethodInfoVisitor(
    282             new BootstrapMethodHandleTraveler(
    283             new MethodrefTraveler(
    284             new ReferencedMemberVisitor(keepMarker))))))));
    285 
    286         // We also keep all bootstrap method arguments that point to methods.
    287         // These arguments are typically the method handles for
    288         // java.lang.invoke.LambdaMetafactory#metafactory, which provides the
    289         // implementations for closures.
    290         programClassPool.classesAccept(
    291             new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
    292             new AllAttributeVisitor(
    293             new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods,
    294             new AllBootstrapMethodInfoVisitor(
    295             new BootstrapMethodArgumentVisitor(
    296             new MethodrefTraveler(
    297             new ReferencedMemberVisitor(keepMarker))))))));
    298 
    299         // We also keep all classes (and their methods) returned by dynamic
    300         // method invocations. They may return dynamic implementations of
    301         // interfaces that otherwise appear unused.
    302         programClassPool.classesAccept(
    303             new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7,
    304             new AllConstantVisitor(
    305             new DynamicReturnedClassVisitor(
    306             new MultiClassVisitor(new ClassVisitor[]
    307             {
    308                 keepMarker,
    309                 new AllMemberVisitor(keepMarker)
    310             })))));
    311 
    312         // Attach some optimization info to all classes and class members, so
    313         // it can be filled out later.
    314         programClassPool.classesAccept(new ClassOptimizationInfoSetter());
    315 
    316         programClassPool.classesAccept(new AllMemberVisitor(
    317                                        new MemberOptimizationInfoSetter()));
    318 
    319         if (configuration.assumeNoSideEffects != null)
    320         {
    321             // Create a visitor for marking methods that don't have any side effects.
    322             NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker();
    323             ClassPoolVisitor noClassPoolvisitor =
    324                 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects,
    325                                                                         null,
    326                                                                         noSideEffectMethodMarker);
    327 
    328             // Mark the seeds.
    329             programClassPool.accept(noClassPoolvisitor);
    330             libraryClassPool.accept(noClassPoolvisitor);
    331         }
    332 
    333         if (classMarkingFinal)
    334         {
    335             // Make classes final, whereever possible.
    336             programClassPool.classesAccept(
    337                 new ClassFinalizer(classMarkingFinalCounter));
    338         }
    339 
    340         if (methodMarkingFinal)
    341         {
    342             // Make methods final, whereever possible.
    343             programClassPool.classesAccept(
    344                 new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
    345                 new AllMethodVisitor(
    346                 new MethodFinalizer(methodMarkingFinalCounter))));
    347         }
    348 
    349         if (fieldRemovalWriteonly)
    350         {
    351             // Mark all fields that are write-only.
    352             programClassPool.classesAccept(
    353                 new AllMethodVisitor(
    354                 new AllAttributeVisitor(
    355                 new AllInstructionVisitor(
    356                 new ReadWriteFieldMarker()))));
    357 
    358             // Count the write-only fields.
    359             programClassPool.classesAccept(
    360                 new AllFieldVisitor(
    361                 new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter)));
    362         }
    363         else
    364         {
    365             // Mark all fields as read/write.
    366             programClassPool.classesAccept(
    367                 new AllFieldVisitor(
    368                 new ReadWriteFieldMarker()));
    369         }
    370 
    371         if (classUnboxingEnum)
    372         {
    373              ClassCounter counter = new ClassCounter();
    374 
    375             // Mark all final enums that qualify as simple enums.
    376             programClassPool.classesAccept(
    377                 new ClassAccessFilter(ClassConstants.ACC_FINAL |
    378                                       ClassConstants.ACC_ENUM, 0,
    379                 new SimpleEnumClassChecker()));
    380 
    381             // Count the preliminary number of simple enums.
    382             programClassPool.classesAccept(
    383                 new SimpleEnumFilter(counter));
    384 
    385             // Only continue checking simple enums if there are any candidates.
    386             if (counter.getCount() > 0)
    387             {
    388                 // Unmark all simple enums that are explicitly used as objects.
    389                 programClassPool.classesAccept(
    390                     new SimpleEnumUseChecker());
    391 
    392                 // Count the definitive number of simple enums.
    393                 programClassPool.classesAccept(
    394                     new SimpleEnumFilter(classUnboxingEnumCounter));
    395 
    396                 // Only start handling simple enums if there are any.
    397                 if (classUnboxingEnumCounter.getCount() > 0)
    398                 {
    399                     // Simplify the use of the enum classes in code.
    400                     programClassPool.classesAccept(
    401                         new AllMethodVisitor(
    402                         new AllAttributeVisitor(
    403                         new SimpleEnumUseSimplifier())));
    404 
    405                     // Simplify the static initializers of simple enum classes.
    406                     programClassPool.classesAccept(
    407                         new SimpleEnumFilter(
    408                         new SimpleEnumClassSimplifier()));
    409 
    410                     // Simplify the use of the enum classes in descriptors.
    411                     programClassPool.classesAccept(
    412                         new SimpleEnumDescriptorSimplifier());
    413 
    414                     // Update references to class members with simple enum classes.
    415                     programClassPool.classesAccept(new MemberReferenceFixer());
    416                 }
    417             }
    418         }
    419 
    420         // Mark all used parameters, including the 'this' parameters.
    421         programClassPool.classesAccept(
    422             new AllMethodVisitor(
    423             new OptimizationInfoMemberFilter(
    424             new ParameterUsageMarker(!methodMarkingStatic,
    425                                      !methodRemovalParameter))));
    426 
    427         // Mark all classes that have static initializers.
    428         programClassPool.classesAccept(new StaticInitializerContainingClassMarker());
    429 
    430         // Mark all methods that have side effects.
    431         programClassPool.accept(new SideEffectMethodMarker());
    432 
    433 //        System.out.println("Optimizer.execute: before evaluation simplification");
    434 //        programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter()));
    435 
    436         // Perform partial evaluation for filling out fields, method parameters,
    437         // and method return values, so they can be propagated.
    438         if (fieldPropagationValue      ||
    439             methodPropagationParameter ||
    440             methodPropagationReturnvalue)
    441         {
    442             // We'll create values to be stored with fields, method parameters,
    443             // and return values.
    444             ValueFactory valueFactory         = new ParticularValueFactory();
    445             ValueFactory detailedValueFactory = new DetailedValueFactory();
    446 
    447             InvocationUnit storingInvocationUnit =
    448                 new StoringInvocationUnit(valueFactory,
    449                                           fieldPropagationValue,
    450                                           methodPropagationParameter,
    451                                           methodPropagationReturnvalue);
    452 
    453             // Evaluate synthetic classes in more detail, notably to propagate
    454             // the arrays of the classes generated for enum switch statements.
    455             programClassPool.classesAccept(
    456                 new ClassAccessFilter(ClassConstants.ACC_SYNTHETIC, 0,
    457                 new AllMethodVisitor(
    458                 new AllAttributeVisitor(
    459                 new PartialEvaluator(detailedValueFactory, storingInvocationUnit, false)))));
    460 
    461             // Evaluate non-synthetic classes.
    462             programClassPool.classesAccept(
    463                 new ClassAccessFilter(0, ClassConstants.ACC_SYNTHETIC,
    464                 new AllMethodVisitor(
    465                 new AllAttributeVisitor(
    466                 new PartialEvaluator(valueFactory, storingInvocationUnit, false)))));
    467 
    468             if (fieldPropagationValue)
    469             {
    470                 // Count the constant fields.
    471                 programClassPool.classesAccept(
    472                     new AllFieldVisitor(
    473                     new ConstantMemberFilter(fieldPropagationValueCounter)));
    474             }
    475 
    476             if (methodPropagationParameter)
    477             {
    478                 // Count the constant method parameters.
    479                 programClassPool.classesAccept(
    480                     new AllMethodVisitor(
    481                     new ConstantParameterFilter(methodPropagationParameterCounter)));
    482             }
    483 
    484             if (methodPropagationReturnvalue)
    485             {
    486                 // Count the constant method return values.
    487                 programClassPool.classesAccept(
    488                     new AllMethodVisitor(
    489                     new ConstantMemberFilter(methodPropagationReturnvalueCounter)));
    490             }
    491 
    492             if (classUnboxingEnumCounter.getCount() > 0)
    493             {
    494                 // Propagate the simple enum constant counts.
    495                 programClassPool.classesAccept(
    496                     new SimpleEnumFilter(
    497                     new SimpleEnumArrayPropagator()));
    498             }
    499 
    500             if (codeSimplificationAdvanced)
    501             {
    502                 // Fill out constants into the arrays of synthetic classes,
    503                 // notably the arrays of the classes generated for enum switch
    504                 // statements.
    505                 InvocationUnit loadingInvocationUnit =
    506                     new LoadingInvocationUnit(valueFactory,
    507                                               fieldPropagationValue,
    508                                               methodPropagationParameter,
    509                                               methodPropagationReturnvalue);
    510 
    511                 programClassPool.classesAccept(
    512                     new ClassAccessFilter(ClassConstants.ACC_SYNTHETIC, 0,
    513                     new AllMethodVisitor(
    514                     new AllAttributeVisitor(
    515                     new PartialEvaluator(valueFactory, loadingInvocationUnit, false)))));
    516             }
    517         }
    518 
    519         // Perform partial evaluation again, now loading any previously stored
    520         // values for fields, method parameters, and method return values.
    521         ValueFactory valueFactory = new IdentifiedValueFactory();
    522 
    523         InvocationUnit loadingInvocationUnit =
    524             new LoadingInvocationUnit(valueFactory,
    525                                       fieldPropagationValue,
    526                                       methodPropagationParameter,
    527                                       methodPropagationReturnvalue);
    528 
    529         if (codeSimplificationAdvanced)
    530         {
    531             // Simplify based on partial evaluation, propagating constant
    532             // field values, method parameter values, and return values.
    533             programClassPool.classesAccept(
    534                 new AllMethodVisitor(
    535                 new AllAttributeVisitor(
    536                 new EvaluationSimplifier(
    537                 new PartialEvaluator(valueFactory, loadingInvocationUnit, false),
    538                 codeSimplificationAdvancedCounter))));
    539         }
    540 
    541         if (codeRemovalAdvanced)
    542         {
    543             // Remove code based on partial evaluation, also removing unused
    544             // parameters from method invocations, and making methods static
    545             // if possible.
    546             programClassPool.classesAccept(
    547                 new AllMethodVisitor(
    548                 new AllAttributeVisitor(
    549                 new EvaluationShrinker(
    550                 new PartialEvaluator(valueFactory, loadingInvocationUnit, !codeSimplificationAdvanced),
    551                 deletedCounter, addedCounter))));
    552         }
    553 
    554         if (methodRemovalParameter)
    555         {
    556             // Shrink the parameters in the method descriptors.
    557             programClassPool.classesAccept(
    558                 new AllMethodVisitor(
    559                 new OptimizationInfoMemberFilter(
    560                 new MethodDescriptorShrinker())));
    561         }
    562 
    563         if (methodMarkingStatic)
    564         {
    565             // Make all non-static methods that don't require the 'this'
    566             // parameter static.
    567             programClassPool.classesAccept(
    568                 new AllMethodVisitor(
    569                 new OptimizationInfoMemberFilter(
    570                 new MemberAccessFilter(0, ClassConstants.ACC_STATIC,
    571                 new MethodStaticizer(methodMarkingStaticCounter)))));
    572         }
    573 
    574         if (methodRemovalParameter)
    575         {
    576             // Fix all references to class members.
    577             // This operation also updates the stack sizes.
    578             programClassPool.classesAccept(
    579                 new MemberReferenceFixer());
    580 
    581             // Remove unused bootstrap method arguments.
    582             programClassPool.classesAccept(
    583                 new AllAttributeVisitor(
    584                 new AllBootstrapMethodInfoVisitor(
    585                 new BootstrapMethodArgumentShrinker())));
    586         }
    587 
    588         if (methodRemovalParameter ||
    589             methodMarkingPrivate   ||
    590             methodMarkingStatic)
    591         {
    592             // Remove all unused parameters from the byte code, shifting all
    593             // remaining variables.
    594             // This operation also updates the local variable frame sizes.
    595             programClassPool.classesAccept(
    596                 new AllMethodVisitor(
    597                 new AllAttributeVisitor(
    598                 new ParameterShrinker(methodRemovalParameterCounter))));
    599         }
    600         else if (codeRemovalAdvanced)
    601         {
    602             // Just update the local variable frame sizes.
    603             programClassPool.classesAccept(
    604                 new AllMethodVisitor(
    605                 new AllAttributeVisitor(
    606                 new StackSizeUpdater())));
    607         }
    608 
    609         if (methodRemovalParameter &&
    610             methodRemovalParameterCounter.getCount() > 0)
    611         {
    612             // Tweak the descriptors of duplicate initializers, due to removed
    613             // method parameters.
    614             programClassPool.classesAccept(
    615                 new AllMethodVisitor(
    616                 new DuplicateInitializerFixer(initializerFixCounter1)));
    617 
    618             if (initializerFixCounter1.getCount() > 0)
    619             {
    620                 // Fix all invocations of tweaked initializers.
    621                 programClassPool.classesAccept(
    622                     new AllMethodVisitor(
    623                     new AllAttributeVisitor(
    624                     new DuplicateInitializerInvocationFixer(addedCounter))));
    625 
    626                 // Fix all references to tweaked initializers.
    627                 programClassPool.classesAccept(new MemberReferenceFixer());
    628             }
    629         }
    630 
    631         //// Specializing the class member descriptors seems to increase the
    632         //// class file size, on average.
    633         //// Specialize all class member descriptors.
    634         //programClassPool.classesAccept(new AllMemberVisitor(
    635         //                               new OptimizationInfoMemberFilter(
    636         //                               new MemberDescriptorSpecializer())));
    637         //
    638         //// Fix all references to classes, for MemberDescriptorSpecializer.
    639         //programClassPool.classesAccept(new AllMemberVisitor(
    640         //                               new OptimizationInfoMemberFilter(
    641         //                               new ClassReferenceFixer(true))));
    642 
    643         // Mark all classes with package visible members.
    644         // Mark all exception catches of methods.
    645         // Count all method invocations.
    646         // Mark super invocations and other access of methods.
    647         programClassPool.classesAccept(
    648             new MultiClassVisitor(
    649             new ClassVisitor[]
    650             {
    651                 new PackageVisibleMemberContainingClassMarker(),
    652                 new AllConstantVisitor(
    653                 new PackageVisibleMemberInvokingClassMarker()),
    654                 new AllMethodVisitor(
    655                 new MultiMemberVisitor(
    656                 new MemberVisitor[]
    657                 {
    658                     new AllAttributeVisitor(
    659                     new MultiAttributeVisitor(
    660                     new AttributeVisitor[]
    661                     {
    662                         new CatchExceptionMarker(),
    663                         new AllInstructionVisitor(
    664                         new MultiInstructionVisitor(
    665                         new InstructionVisitor[]
    666                         {
    667                             new InstantiationClassMarker(),
    668                             new InstanceofClassMarker(),
    669                             new DotClassMarker(),
    670                             new MethodInvocationMarker(),
    671                             new SuperInvocationMarker(),
    672                             new DynamicInvocationMarker(),
    673                             new BackwardBranchMarker(),
    674                             new AccessMethodMarker(),
    675                         })),
    676                         new AllExceptionInfoVisitor(
    677                         new ExceptionHandlerConstantVisitor(
    678                         new ReferencedClassVisitor(
    679                         new CaughtClassMarker()))),
    680                     })),
    681                 })),
    682             }));
    683 
    684         if (classMergingVertical)
    685         {
    686             // Merge subclasses up into their superclasses or
    687             // merge interfaces down into their implementing classes.
    688             programClassPool.classesAccept(
    689                 new VerticalClassMerger(configuration.allowAccessModification,
    690                                         configuration.mergeInterfacesAggressively,
    691                                         classMergingVerticalCounter));
    692         }
    693 
    694         if (classMergingHorizontal)
    695         {
    696             // Merge classes into their sibling classes.
    697             programClassPool.classesAccept(
    698                 new HorizontalClassMerger(configuration.allowAccessModification,
    699                                           configuration.mergeInterfacesAggressively,
    700                                           classMergingHorizontalCounter));
    701         }
    702 
    703         if (classMergingVerticalCounter  .getCount() > 0 ||
    704             classMergingHorizontalCounter.getCount() > 0)
    705         {
    706             // Clean up inner class attributes to avoid loops.
    707             programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover());
    708 
    709             // Update references to merged classes.
    710             programClassPool.classesAccept(new TargetClassChanger());
    711             programClassPool.classesAccept(new ClassReferenceFixer(true));
    712             programClassPool.classesAccept(new MemberReferenceFixer());
    713 
    714             if (configuration.allowAccessModification)
    715             {
    716                 // Fix the access flags of referenced merged classes and their
    717                 // class members.
    718                 programClassPool.classesAccept(
    719                     new AccessFixer());
    720             }
    721 
    722             // Fix the access flags of the inner classes information.
    723             programClassPool.classesAccept(
    724                 new AllAttributeVisitor(
    725                 new AllInnerClassesInfoVisitor(
    726                 new InnerClassesAccessFixer())));
    727 
    728             // Tweak the descriptors of duplicate initializers, due to merged
    729             // parameter classes.
    730             programClassPool.classesAccept(
    731                 new AllMethodVisitor(
    732                 new DuplicateInitializerFixer(initializerFixCounter2)));
    733 
    734             if (initializerFixCounter2.getCount() > 0)
    735             {
    736                 // Fix all invocations of tweaked initializers.
    737                 programClassPool.classesAccept(
    738                     new AllMethodVisitor(
    739                     new AllAttributeVisitor(
    740                     new DuplicateInitializerInvocationFixer(addedCounter))));
    741 
    742                 // Fix all references to tweaked initializers.
    743                 programClassPool.classesAccept(new MemberReferenceFixer());
    744             }
    745         }
    746 
    747         if (methodInliningUnique)
    748         {
    749             // Inline methods that are only invoked once.
    750             programClassPool.classesAccept(
    751                 new AllMethodVisitor(
    752                 new AllAttributeVisitor(
    753                 new MethodInliner(configuration.microEdition,
    754                                   configuration.allowAccessModification,
    755                                   true,
    756                                   methodInliningUniqueCounter))));
    757         }
    758 
    759         if (methodInliningShort)
    760         {
    761             // Inline short methods.
    762             programClassPool.classesAccept(
    763                 new AllMethodVisitor(
    764                 new AllAttributeVisitor(
    765                 new MethodInliner(configuration.microEdition,
    766                                   configuration.allowAccessModification,
    767                                   false,
    768                                   methodInliningShortCounter))));
    769         }
    770 
    771         if (methodInliningTailrecursion)
    772         {
    773             // Simplify tail recursion calls.
    774             programClassPool.classesAccept(
    775                 new AllMethodVisitor(
    776                 new AllAttributeVisitor(
    777                 new TailRecursionSimplifier(methodInliningTailrecursionCounter))));
    778         }
    779 
    780         if (fieldMarkingPrivate ||
    781             methodMarkingPrivate)
    782         {
    783             // Mark all class members that can not be made private.
    784             programClassPool.classesAccept(
    785                 new NonPrivateMemberMarker());
    786         }
    787 
    788         if (fieldMarkingPrivate)
    789         {
    790             // Make all non-private fields private, whereever possible.
    791             programClassPool.classesAccept(
    792                 new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
    793                 new AllFieldVisitor(
    794                 new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
    795                 new MemberPrivatizer(fieldMarkingPrivateCounter)))));
    796         }
    797 
    798         if (methodMarkingPrivate)
    799         {
    800             // Make all non-private methods private, whereever possible.
    801             programClassPool.classesAccept(
    802                 new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE,
    803                 new AllMethodVisitor(
    804                 new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE,
    805                 new MemberPrivatizer(methodMarkingPrivateCounter)))));
    806         }
    807 
    808         if ((methodInliningUniqueCounter       .getCount() > 0 ||
    809              methodInliningShortCounter        .getCount() > 0 ||
    810              methodInliningTailrecursionCounter.getCount() > 0) &&
    811             configuration.allowAccessModification)
    812         {
    813             // Fix the access flags of referenced classes and class members,
    814             // for MethodInliner.
    815             programClassPool.classesAccept(
    816                 new AccessFixer());
    817         }
    818 
    819         if (methodRemovalParameterCounter .getCount() > 0 ||
    820             classMergingVerticalCounter   .getCount() > 0 ||
    821             classMergingHorizontalCounter .getCount() > 0 ||
    822             methodMarkingPrivateCounter   .getCount() > 0 )
    823         {
    824             // Fix invocations of interface methods, of methods that have become
    825             // non-abstract or private, and of methods that have moved to a
    826             // different package.
    827             programClassPool.classesAccept(
    828                 new AllMemberVisitor(
    829                 new AllAttributeVisitor(
    830                 new MethodInvocationFixer())));
    831         }
    832 
    833         if (codeMerging)
    834         {
    835             // Share common blocks of code at branches.
    836             programClassPool.classesAccept(
    837                 new AllMethodVisitor(
    838                 new AllAttributeVisitor(
    839                 new GotoCommonCodeReplacer(codeMergingCounter))));
    840         }
    841 
    842         // Create a branch target marker and a code attribute editor that can
    843         // be reused for all code attributes.
    844         BranchTargetFinder  branchTargetFinder  = new BranchTargetFinder();
    845         CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
    846 
    847         List peepholeOptimizations = new ArrayList();
    848         if (codeSimplificationVariable)
    849         {
    850             // Peephole optimizations involving local variables.
    851             peepholeOptimizations.add(
    852                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    853                                                  InstructionSequenceConstants.VARIABLE,
    854                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter));
    855         }
    856 
    857         if (codeSimplificationArithmetic)
    858         {
    859             // Peephole optimizations involving arithmetic operations.
    860             peepholeOptimizations.add(
    861                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    862                                                  InstructionSequenceConstants.ARITHMETIC,
    863                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter));
    864         }
    865 
    866         if (codeSimplificationCast)
    867         {
    868             // Peephole optimizations involving cast operations.
    869             peepholeOptimizations.add(
    870                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    871                                                  InstructionSequenceConstants.CAST,
    872                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter));
    873         }
    874 
    875         if (codeSimplificationField)
    876         {
    877             // Peephole optimizations involving fields.
    878             peepholeOptimizations.add(
    879                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    880                                                  InstructionSequenceConstants.FIELD,
    881                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter));
    882         }
    883 
    884         if (codeSimplificationBranch)
    885         {
    886             // Peephole optimizations involving branches.
    887             peepholeOptimizations.add(
    888                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    889                                                  InstructionSequenceConstants.BRANCH,
    890                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter));
    891 
    892             // Include optimization of branches to branches and returns.
    893             peepholeOptimizations.add(
    894                 new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter));
    895             peepholeOptimizations.add(
    896                 new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter));
    897         }
    898 
    899         if (codeSimplificationString)
    900         {
    901             // Peephole optimizations involving branches.
    902             peepholeOptimizations.add(
    903                 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS,
    904                                                  InstructionSequenceConstants.STRING,
    905                                                  branchTargetFinder, codeAttributeEditor, codeSimplificationStringCounter));
    906         }
    907 
    908         if (!peepholeOptimizations.isEmpty())
    909         {
    910             // Convert the list into an array.
    911             InstructionVisitor[] peepholeOptimizationsArray =
    912                 new InstructionVisitor[peepholeOptimizations.size()];
    913             peepholeOptimizations.toArray(peepholeOptimizationsArray);
    914 
    915             // Perform the peephole optimisations.
    916             programClassPool.classesAccept(
    917                 new AllMethodVisitor(
    918                 new AllAttributeVisitor(
    919                 new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor,
    920                 new MultiInstructionVisitor(
    921                 peepholeOptimizationsArray)))));
    922         }
    923 
    924         if (codeRemovalException)
    925         {
    926             // Remove unnecessary exception handlers.
    927             programClassPool.classesAccept(
    928                 new AllMethodVisitor(
    929                 new AllAttributeVisitor(
    930                 new UnreachableExceptionRemover(codeRemovalExceptionCounter))));
    931         }
    932 
    933         if (codeRemovalSimple)
    934         {
    935             // Remove unreachable code.
    936             programClassPool.classesAccept(
    937                 new AllMethodVisitor(
    938                 new AllAttributeVisitor(
    939                 new UnreachableCodeRemover(deletedCounter))));
    940         }
    941 
    942         if (codeRemovalVariable)
    943         {
    944             // Remove all unused local variables.
    945             programClassPool.classesAccept(
    946                 new AllMethodVisitor(
    947                 new AllAttributeVisitor(
    948                 new VariableShrinker(codeRemovalVariableCounter))));
    949         }
    950 
    951         if (codeAllocationVariable)
    952         {
    953             // Optimize the variables.
    954             programClassPool.classesAccept(
    955                 new AllMethodVisitor(
    956                 new AllAttributeVisitor(
    957                 new VariableOptimizer(false, codeAllocationVariableCounter))));
    958         }
    959 
    960 
    961         // Remove unused constants.
    962         programClassPool.classesAccept(
    963             new ConstantPoolShrinker());
    964 
    965         int classMarkingFinalCount            = classMarkingFinalCounter           .getCount();
    966         int classUnboxingEnumCount            = classUnboxingEnumCounter           .getCount();
    967         int classMergingVerticalCount         = classMergingVerticalCounter        .getCount();
    968         int classMergingHorizontalCount       = classMergingHorizontalCounter      .getCount();
    969         int fieldRemovalWriteonlyCount        = fieldRemovalWriteonlyCounter       .getCount();
    970         int fieldMarkingPrivateCount          = fieldMarkingPrivateCounter         .getCount();
    971         int fieldPropagationValueCount        = fieldPropagationValueCounter       .getCount();
    972         int methodMarkingPrivateCount         = methodMarkingPrivateCounter        .getCount();
    973         int methodMarkingStaticCount          = methodMarkingStaticCounter         .getCount();
    974         int methodMarkingFinalCount           = methodMarkingFinalCounter          .getCount();
    975         int methodRemovalParameterCount       = methodRemovalParameterCounter      .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount();
    976         int methodPropagationParameterCount   = methodPropagationParameterCounter  .getCount();
    977         int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount();
    978         int methodInliningShortCount          = methodInliningShortCounter         .getCount();
    979         int methodInliningUniqueCount         = methodInliningUniqueCounter        .getCount();
    980         int methodInliningTailrecursionCount  = methodInliningTailrecursionCounter .getCount();
    981         int codeMergingCount                  = codeMergingCounter                 .getCount();
    982         int codeSimplificationVariableCount   = codeSimplificationVariableCounter  .getCount();
    983         int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter.getCount();
    984         int codeSimplificationCastCount       = codeSimplificationCastCounter      .getCount();
    985         int codeSimplificationFieldCount      = codeSimplificationFieldCounter     .getCount();
    986         int codeSimplificationBranchCount     = codeSimplificationBranchCounter    .getCount();
    987         int codeSimplificationStringCount     = codeSimplificationStringCounter    .getCount();
    988         int codeSimplificationAdvancedCount   = codeSimplificationAdvancedCounter  .getCount();
    989         int codeRemovalCount                  = deletedCounter                     .getCount() - addedCounter.getCount();
    990         int codeRemovalVariableCount          = codeRemovalVariableCounter         .getCount();
    991         int codeRemovalExceptionCount         = codeRemovalExceptionCounter        .getCount();
    992         int codeAllocationVariableCount       = codeAllocationVariableCounter      .getCount();
    993 
    994         // Forget about constant fields, parameters, and return values, if they
    995         // didn't lead to any useful optimizations. We want to avoid fruitless
    996         // additional optimization passes.
    997         if (codeSimplificationAdvancedCount == 0)
    998         {
    999             fieldPropagationValueCount        = 0;
   1000             methodPropagationParameterCount   = 0;
   1001             methodPropagationReturnvalueCount = 0;
   1002         }
   1003 
   1004         if (configuration.verbose)
   1005         {
   1006             System.out.println("  Number of finalized classes:                 " + classMarkingFinalCount            + disabled(classMarkingFinal));
   1007             System.out.println("  Number of unboxed enum classes:              " + classUnboxingEnumCount            + disabled(classUnboxingEnum));
   1008             System.out.println("  Number of vertically merged classes:         " + classMergingVerticalCount         + disabled(classMergingVertical));
   1009             System.out.println("  Number of horizontally merged classes:       " + classMergingHorizontalCount       + disabled(classMergingHorizontal));
   1010             System.out.println("  Number of removed write-only fields:         " + fieldRemovalWriteonlyCount        + disabled(fieldRemovalWriteonly));
   1011             System.out.println("  Number of privatized fields:                 " + fieldMarkingPrivateCount          + disabled(fieldMarkingPrivate));
   1012             System.out.println("  Number of inlined constant fields:           " + fieldPropagationValueCount        + disabled(fieldPropagationValue));
   1013             System.out.println("  Number of privatized methods:                " + methodMarkingPrivateCount         + disabled(methodMarkingPrivate));
   1014             System.out.println("  Number of staticized methods:                " + methodMarkingStaticCount          + disabled(methodMarkingStatic));
   1015             System.out.println("  Number of finalized methods:                 " + methodMarkingFinalCount           + disabled(methodMarkingFinal));
   1016             System.out.println("  Number of removed method parameters:         " + methodRemovalParameterCount       + disabled(methodRemovalParameter));
   1017             System.out.println("  Number of inlined constant parameters:       " + methodPropagationParameterCount   + disabled(methodPropagationParameter));
   1018             System.out.println("  Number of inlined constant return values:    " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue));
   1019             System.out.println("  Number of inlined short method calls:        " + methodInliningShortCount          + disabled(methodInliningShort));
   1020             System.out.println("  Number of inlined unique method calls:       " + methodInliningUniqueCount         + disabled(methodInliningUnique));
   1021             System.out.println("  Number of inlined tail recursion calls:      " + methodInliningTailrecursionCount  + disabled(methodInliningTailrecursion));
   1022             System.out.println("  Number of merged code blocks:                " + codeMergingCount                  + disabled(codeMerging));
   1023             System.out.println("  Number of variable peephole optimizations:   " + codeSimplificationVariableCount   + disabled(codeSimplificationVariable));
   1024             System.out.println("  Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic));
   1025             System.out.println("  Number of cast peephole optimizations:       " + codeSimplificationCastCount       + disabled(codeSimplificationCast));
   1026             System.out.println("  Number of field peephole optimizations:      " + codeSimplificationFieldCount      + disabled(codeSimplificationField));
   1027             System.out.println("  Number of branch peephole optimizations:     " + codeSimplificationBranchCount     + disabled(codeSimplificationBranch));
   1028             System.out.println("  Number of string peephole optimizations:     " + codeSimplificationStringCount     + disabled(codeSimplificationString));
   1029             System.out.println("  Number of simplified instructions:           " + codeSimplificationAdvancedCount   + disabled(codeSimplificationAdvanced));
   1030             System.out.println("  Number of removed instructions:              " + codeRemovalCount                  + disabled(codeRemovalAdvanced));
   1031             System.out.println("  Number of removed local variables:           " + codeRemovalVariableCount          + disabled(codeRemovalVariable));
   1032             System.out.println("  Number of removed exception blocks:          " + codeRemovalExceptionCount         + disabled(codeRemovalException));
   1033             System.out.println("  Number of optimized local variable frames:   " + codeAllocationVariableCount       + disabled(codeAllocationVariable));
   1034         }
   1035 
   1036         return classMarkingFinalCount            > 0 ||
   1037                classUnboxingEnumCount            > 0 ||
   1038                classMergingVerticalCount         > 0 ||
   1039                classMergingHorizontalCount       > 0 ||
   1040                fieldRemovalWriteonlyCount        > 0 ||
   1041                fieldMarkingPrivateCount          > 0 ||
   1042                methodMarkingPrivateCount         > 0 ||
   1043                methodMarkingStaticCount          > 0 ||
   1044                methodMarkingFinalCount           > 0 ||
   1045                fieldPropagationValueCount        > 0 ||
   1046                methodRemovalParameterCount       > 0 ||
   1047                methodPropagationParameterCount   > 0 ||
   1048                methodPropagationReturnvalueCount > 0 ||
   1049                methodInliningShortCount          > 0 ||
   1050                methodInliningUniqueCount         > 0 ||
   1051                methodInliningTailrecursionCount  > 0 ||
   1052                codeMergingCount                  > 0 ||
   1053                codeSimplificationVariableCount   > 0 ||
   1054                codeSimplificationArithmeticCount > 0 ||
   1055                codeSimplificationCastCount       > 0 ||
   1056                codeSimplificationFieldCount      > 0 ||
   1057                codeSimplificationBranchCount     > 0 ||
   1058                codeSimplificationStringCount     > 0 ||
   1059                codeSimplificationAdvancedCount   > 0 ||
   1060                codeRemovalCount                  > 0 ||
   1061                codeRemovalVariableCount          > 0 ||
   1062                codeRemovalExceptionCount         > 0 ||
   1063                codeAllocationVariableCount       > 0;
   1064     }
   1065 
   1066 
   1067     /**
   1068      * Returns a String indicating whether the given flag is enabled or
   1069      * disabled.
   1070      */
   1071     private String disabled(boolean flag)
   1072     {
   1073         return flag ? "" : "   (disabled)";
   1074     }
   1075 
   1076 
   1077     /**
   1078      * Returns a String indicating whether the given flags are enabled or
   1079      * disabled.
   1080      */
   1081     private String disabled(boolean flag1, boolean flag2)
   1082     {
   1083         return flag1 && flag2 ? "" :
   1084                flag1 || flag2 ? "   (partially disabled)" :
   1085                                 "   (disabled)";
   1086     }
   1087 }
   1088