Optimizer.java revision 9f606f95f03a75961498803e24bee6799a7c0885
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 Eric Lafortune (eric@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 */
21package proguard.optimize;
22
23import proguard.*;
24import proguard.classfile.*;
25import proguard.classfile.attribute.visitor.*;
26import proguard.classfile.constant.visitor.AllConstantVisitor;
27import proguard.classfile.editor.*;
28import proguard.classfile.instruction.visitor.*;
29import proguard.classfile.util.MethodLinker;
30import proguard.classfile.visitor.*;
31import proguard.evaluation.*;
32import proguard.evaluation.value.*;
33import proguard.optimize.evaluation.*;
34import proguard.optimize.info.*;
35import proguard.optimize.peephole.*;
36import proguard.util.*;
37
38import java.io.IOException;
39import java.util.*;
40
41/**
42 * This class optimizes class pools according to a given configuration.
43 *
44 * @author Eric Lafortune
45 */
46public 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