| /* |
| * ProGuard -- shrinking, optimization, obfuscation, and preverification |
| * of Java bytecode. |
| * |
| * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the Free |
| * Software Foundation; either version 2 of the License, or (at your option) |
| * any later version. |
| * |
| * This program is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
| * more details. |
| * |
| * You should have received a copy of the GNU General Public License along |
| * with this program; if not, write to the Free Software Foundation, Inc., |
| * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| package proguard.optimize; |
| |
| import proguard.*; |
| import proguard.classfile.*; |
| import proguard.classfile.attribute.visitor.*; |
| import proguard.classfile.constant.visitor.AllConstantVisitor; |
| import proguard.classfile.editor.*; |
| import proguard.classfile.instruction.visitor.*; |
| import proguard.classfile.util.MethodLinker; |
| import proguard.classfile.visitor.*; |
| import proguard.evaluation.*; |
| import proguard.evaluation.value.*; |
| import proguard.optimize.evaluation.*; |
| import proguard.optimize.info.*; |
| import proguard.optimize.peephole.*; |
| import proguard.util.*; |
| |
| import java.io.IOException; |
| import java.util.*; |
| |
| /** |
| * This class optimizes class pools according to a given configuration. |
| * |
| * @author Eric Lafortune |
| */ |
| public class Optimizer |
| { |
| private static final String CLASS_MARKING_FINAL = "class/marking/final"; |
| private static final String CLASS_MERGING_VERTICAL = "class/merging/vertical"; |
| private static final String CLASS_MERGING_HORIZONTAL = "class/merging/horizontal"; |
| private static final String FIELD_REMOVAL_WRITEONLY = "field/removal/writeonly"; |
| private static final String FIELD_MARKING_PRIVATE = "field/marking/private"; |
| private static final String FIELD_PROPAGATION_VALUE = "field/propagation/value"; |
| private static final String METHOD_MARKING_PRIVATE = "method/marking/private"; |
| private static final String METHOD_MARKING_STATIC = "method/marking/static"; |
| private static final String METHOD_MARKING_FINAL = "method/marking/final"; |
| private static final String METHOD_REMOVAL_PARAMETER = "method/removal/parameter"; |
| private static final String METHOD_PROPAGATION_PARAMETER = "method/propagation/parameter"; |
| private static final String METHOD_PROPAGATION_RETURNVALUE = "method/propagation/returnvalue"; |
| private static final String METHOD_INLINING_SHORT = "method/inlining/short"; |
| private static final String METHOD_INLINING_UNIQUE = "method/inlining/unique"; |
| private static final String METHOD_INLINING_TAILRECURSION = "method/inlining/tailrecursion"; |
| private static final String CODE_MERGING = "code/merging"; |
| private static final String CODE_SIMPLIFICATION_VARIABLE = "code/simplification/variable"; |
| private static final String CODE_SIMPLIFICATION_ARITHMETIC = "code/simplification/arithmetic"; |
| private static final String CODE_SIMPLIFICATION_CAST = "code/simplification/cast"; |
| private static final String CODE_SIMPLIFICATION_FIELD = "code/simplification/field"; |
| private static final String CODE_SIMPLIFICATION_BRANCH = "code/simplification/branch"; |
| private static final String CODE_SIMPLIFICATION_ADVANCED = "code/simplification/advanced"; |
| private static final String CODE_REMOVAL_ADVANCED = "code/removal/advanced"; |
| private static final String CODE_REMOVAL_SIMPLE = "code/removal/simple"; |
| private static final String CODE_REMOVAL_VARIABLE = "code/removal/variable"; |
| private static final String CODE_REMOVAL_EXCEPTION = "code/removal/exception"; |
| private static final String CODE_ALLOCATION_VARIABLE = "code/allocation/variable"; |
| |
| |
| public static final String[] OPTIMIZATION_NAMES = new String[] |
| { |
| CLASS_MARKING_FINAL, |
| CLASS_MERGING_VERTICAL, |
| CLASS_MERGING_HORIZONTAL, |
| FIELD_REMOVAL_WRITEONLY, |
| FIELD_PROPAGATION_VALUE, |
| METHOD_MARKING_PRIVATE, |
| METHOD_MARKING_STATIC, |
| METHOD_MARKING_FINAL, |
| METHOD_REMOVAL_PARAMETER, |
| METHOD_PROPAGATION_PARAMETER, |
| METHOD_PROPAGATION_RETURNVALUE, |
| METHOD_INLINING_SHORT, |
| METHOD_INLINING_UNIQUE, |
| METHOD_INLINING_TAILRECURSION, |
| CODE_MERGING, |
| CODE_SIMPLIFICATION_VARIABLE, |
| CODE_SIMPLIFICATION_ARITHMETIC, |
| CODE_SIMPLIFICATION_CAST, |
| CODE_SIMPLIFICATION_FIELD, |
| CODE_SIMPLIFICATION_BRANCH, |
| CODE_SIMPLIFICATION_ADVANCED, |
| CODE_REMOVAL_ADVANCED, |
| CODE_REMOVAL_SIMPLE, |
| CODE_REMOVAL_VARIABLE, |
| CODE_REMOVAL_EXCEPTION, |
| CODE_ALLOCATION_VARIABLE, |
| }; |
| |
| |
| private final Configuration configuration; |
| |
| |
| /** |
| * Creates a new Optimizer. |
| */ |
| public Optimizer(Configuration configuration) |
| { |
| this.configuration = configuration; |
| } |
| |
| |
| /** |
| * Performs optimization of the given program class pool. |
| */ |
| public boolean execute(ClassPool programClassPool, |
| ClassPool libraryClassPool) throws IOException |
| { |
| // Check if we have at least some keep commands. |
| if (configuration.keep == null && |
| configuration.applyMapping == null && |
| configuration.printMapping == null) |
| { |
| throw new IOException("You have to specify '-keep' options for the optimization step."); |
| } |
| |
| // Create a matcher for filtering optimizations. |
| StringMatcher filter = configuration.optimizations != null ? |
| new ListParser(new NameParser()).parse(configuration.optimizations) : |
| new ConstantMatcher(true); |
| |
| boolean classMarkingFinal = filter.matches(CLASS_MARKING_FINAL); |
| boolean classMergingVertical = filter.matches(CLASS_MERGING_VERTICAL); |
| boolean classMergingHorizontal = filter.matches(CLASS_MERGING_HORIZONTAL); |
| boolean fieldRemovalWriteonly = filter.matches(FIELD_REMOVAL_WRITEONLY); |
| boolean fieldMarkingPrivate = filter.matches(FIELD_MARKING_PRIVATE); |
| boolean fieldPropagationValue = filter.matches(FIELD_PROPAGATION_VALUE); |
| boolean methodMarkingPrivate = filter.matches(METHOD_MARKING_PRIVATE); |
| boolean methodMarkingStatic = filter.matches(METHOD_MARKING_STATIC); |
| boolean methodMarkingFinal = filter.matches(METHOD_MARKING_FINAL); |
| boolean methodRemovalParameter = filter.matches(METHOD_REMOVAL_PARAMETER); |
| boolean methodPropagationParameter = filter.matches(METHOD_PROPAGATION_PARAMETER); |
| boolean methodPropagationReturnvalue = filter.matches(METHOD_PROPAGATION_RETURNVALUE); |
| boolean methodInliningShort = filter.matches(METHOD_INLINING_SHORT); |
| boolean methodInliningUnique = filter.matches(METHOD_INLINING_UNIQUE); |
| boolean methodInliningTailrecursion = filter.matches(METHOD_INLINING_TAILRECURSION); |
| boolean codeMerging = filter.matches(CODE_MERGING); |
| boolean codeSimplificationVariable = filter.matches(CODE_SIMPLIFICATION_VARIABLE); |
| boolean codeSimplificationArithmetic = filter.matches(CODE_SIMPLIFICATION_ARITHMETIC); |
| boolean codeSimplificationCast = filter.matches(CODE_SIMPLIFICATION_CAST); |
| boolean codeSimplificationField = filter.matches(CODE_SIMPLIFICATION_FIELD); |
| boolean codeSimplificationBranch = filter.matches(CODE_SIMPLIFICATION_BRANCH); |
| boolean codeSimplificationAdvanced = filter.matches(CODE_SIMPLIFICATION_ADVANCED); |
| boolean codeRemovalAdvanced = filter.matches(CODE_REMOVAL_ADVANCED); |
| boolean codeRemovalSimple = filter.matches(CODE_REMOVAL_SIMPLE); |
| boolean codeRemovalVariable = filter.matches(CODE_REMOVAL_VARIABLE); |
| boolean codeRemovalException = filter.matches(CODE_REMOVAL_EXCEPTION); |
| boolean codeAllocationVariable = filter.matches(CODE_ALLOCATION_VARIABLE); |
| |
| // Create counters to count the numbers of optimizations. |
| ClassCounter classMarkingFinalCounter = new ClassCounter(); |
| ClassCounter classMergingVerticalCounter = new ClassCounter(); |
| ClassCounter classMergingHorizontalCounter = new ClassCounter(); |
| MemberCounter fieldRemovalWriteonlyCounter = new MemberCounter(); |
| MemberCounter fieldMarkingPrivateCounter = new MemberCounter(); |
| MemberCounter fieldPropagationValueCounter = new MemberCounter(); |
| MemberCounter methodMarkingPrivateCounter = new MemberCounter(); |
| MemberCounter methodMarkingStaticCounter = new MemberCounter(); |
| MemberCounter methodMarkingFinalCounter = new MemberCounter(); |
| MemberCounter methodRemovalParameterCounter = new MemberCounter(); |
| MemberCounter methodPropagationParameterCounter = new MemberCounter(); |
| MemberCounter methodPropagationReturnvalueCounter = new MemberCounter(); |
| InstructionCounter methodInliningShortCounter = new InstructionCounter(); |
| InstructionCounter methodInliningUniqueCounter = new InstructionCounter(); |
| InstructionCounter methodInliningTailrecursionCounter = new InstructionCounter(); |
| InstructionCounter codeMergingCounter = new InstructionCounter(); |
| InstructionCounter codeSimplificationVariableCounter = new InstructionCounter(); |
| InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter(); |
| InstructionCounter codeSimplificationCastCounter = new InstructionCounter(); |
| InstructionCounter codeSimplificationFieldCounter = new InstructionCounter(); |
| InstructionCounter codeSimplificationBranchCounter = new InstructionCounter(); |
| InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter(); |
| InstructionCounter deletedCounter = new InstructionCounter(); |
| InstructionCounter addedCounter = new InstructionCounter(); |
| MemberCounter codeRemovalVariableCounter = new MemberCounter(); |
| ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter(); |
| MemberCounter codeAllocationVariableCounter = new MemberCounter(); |
| MemberCounter initializerFixCounter = new MemberCounter(); |
| |
| // Some optimizations are required by other optimizations. |
| codeSimplificationAdvanced = |
| codeSimplificationAdvanced || |
| fieldPropagationValue || |
| methodPropagationParameter || |
| methodPropagationReturnvalue; |
| |
| codeRemovalAdvanced = |
| codeRemovalAdvanced || |
| fieldRemovalWriteonly || |
| methodMarkingStatic || |
| methodRemovalParameter; |
| |
| codeRemovalSimple = |
| codeRemovalSimple || |
| codeSimplificationBranch; |
| |
| codeRemovalException = |
| codeRemovalException || |
| codeRemovalAdvanced || |
| codeRemovalSimple; |
| |
| // Clean up any old visitor info. |
| programClassPool.classesAccept(new ClassCleaner()); |
| libraryClassPool.classesAccept(new ClassCleaner()); |
| |
| // Link all methods that should get the same optimization info. |
| programClassPool.classesAccept(new BottomClassFilter( |
| new MethodLinker())); |
| libraryClassPool.classesAccept(new BottomClassFilter( |
| new MethodLinker())); |
| |
| // Create a visitor for marking the seeds. |
| KeepMarker keepMarker = new KeepMarker(); |
| ClassPoolVisitor classPoolvisitor = |
| ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, |
| keepMarker, |
| keepMarker, |
| false, |
| true, |
| false); |
| // Mark the seeds. |
| programClassPool.accept(classPoolvisitor); |
| libraryClassPool.accept(classPoolvisitor); |
| |
| // All library classes and library class members remain unchanged. |
| libraryClassPool.classesAccept(keepMarker); |
| libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker)); |
| |
| // We also keep all classes that are involved in .class constructs. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new AllInstructionVisitor( |
| new DotClassClassVisitor(keepMarker))))); |
| |
| // We also keep all classes that are involved in Class.forName constructs. |
| programClassPool.classesAccept( |
| new AllConstantVisitor( |
| new ClassForNameClassVisitor(keepMarker))); |
| |
| // Attach some optimization info to all classes and class members, so |
| // it can be filled out later. |
| programClassPool.classesAccept(new ClassOptimizationInfoSetter()); |
| |
| programClassPool.classesAccept(new AllMemberVisitor( |
| new MemberOptimizationInfoSetter())); |
| |
| if (configuration.assumeNoSideEffects != null) |
| { |
| // Create a visitor for marking methods that don't have any side effects. |
| NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker(); |
| ClassPoolVisitor noClassPoolvisitor = |
| ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects, |
| null, |
| noSideEffectMethodMarker); |
| |
| // Mark the seeds. |
| programClassPool.accept(noClassPoolvisitor); |
| libraryClassPool.accept(noClassPoolvisitor); |
| } |
| |
| if (classMarkingFinal) |
| { |
| // Make classes final, whereever possible. |
| programClassPool.classesAccept( |
| new ClassFinalizer(classMarkingFinalCounter)); |
| } |
| |
| if (methodMarkingFinal) |
| { |
| // Make methods final, whereever possible. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new MethodFinalizer(methodMarkingFinalCounter))); |
| } |
| |
| if (fieldRemovalWriteonly) |
| { |
| // Mark all fields that are write-only. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new AllInstructionVisitor( |
| new ReadWriteFieldMarker())))); |
| |
| // Count the write-only fields. |
| programClassPool.classesAccept( |
| new AllFieldVisitor( |
| new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter))); |
| } |
| else |
| { |
| // Mark all fields as read/write. |
| programClassPool.classesAccept( |
| new AllFieldVisitor( |
| new ReadWriteFieldMarker())); |
| } |
| |
| // Mark all used parameters, including the 'this' parameters. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new OptimizationInfoMemberFilter( |
| new ParameterUsageMarker(!methodMarkingStatic, |
| !methodRemovalParameter)))); |
| |
| // Mark all methods that have side effects. |
| programClassPool.accept(new SideEffectMethodMarker()); |
| |
| // System.out.println("Optimizer.execute: before evaluation simplification"); |
| // programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter())); |
| |
| // Perform partial evaluation for filling out fields, method parameters, |
| // and method return values. |
| ValueFactory valueFactory = new IdentifiedValueFactory(); |
| |
| if (fieldPropagationValue || |
| methodPropagationParameter || |
| methodPropagationReturnvalue) |
| { |
| // Fill out fields, method parameters, and return values, so they |
| // can be propagated. |
| InvocationUnit storingInvocationUnit = |
| new StoringInvocationUnit(valueFactory, |
| fieldPropagationValue, |
| methodPropagationParameter, |
| methodPropagationReturnvalue); |
| |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new PartialEvaluator(valueFactory, storingInvocationUnit, false)))); |
| |
| // Count the constant fields and methods. |
| programClassPool.classesAccept( |
| new MultiClassVisitor( |
| new ClassVisitor[] |
| { |
| new AllFieldVisitor( |
| new ConstantMemberFilter(fieldPropagationValueCounter)), |
| new AllMethodVisitor( |
| new ConstantParameterFilter(methodPropagationParameterCounter)), |
| new AllMethodVisitor( |
| new ConstantMemberFilter(methodPropagationReturnvalueCounter)), |
| })); |
| } |
| |
| InvocationUnit loadingInvocationUnit = |
| new LoadingInvocationUnit(valueFactory, |
| fieldPropagationValue, |
| methodPropagationParameter, |
| methodPropagationReturnvalue); |
| |
| if (codeSimplificationAdvanced) |
| { |
| // Simplify based on partial evaluation, propagating constant |
| // field values, method parameter values, and return values. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new EvaluationSimplifier( |
| new PartialEvaluator(valueFactory, loadingInvocationUnit, false), |
| codeSimplificationAdvancedCounter)))); |
| } |
| |
| if (codeRemovalAdvanced) |
| { |
| // Remove code based on partial evaluation, also removing unused |
| // parameters from method invocations, and making methods static |
| // if possible. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new EvaluationShrinker( |
| new PartialEvaluator(valueFactory, loadingInvocationUnit, !codeSimplificationAdvanced), |
| deletedCounter, addedCounter)))); |
| } |
| |
| if (methodRemovalParameter) |
| { |
| // Shrink the parameters in the method descriptors. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new OptimizationInfoMemberFilter( |
| new MethodDescriptorShrinker()))); |
| } |
| |
| if (methodMarkingStatic) |
| { |
| // Make all non-static methods that don't require the 'this' |
| // parameter static. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new OptimizationInfoMemberFilter( |
| new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC, |
| new MethodStaticizer(methodMarkingStaticCounter))))); |
| } |
| |
| if (methodRemovalParameter) |
| { |
| // Fix all references to class members. |
| // This operation also updates the stack sizes. |
| programClassPool.classesAccept( |
| new MemberReferenceFixer()); |
| } |
| |
| if (methodRemovalParameter || |
| methodMarkingPrivate || |
| methodMarkingStatic) |
| { |
| // Remove all unused parameters from the byte code, shifting all |
| // remaining variables. |
| // This operation also updates the local variable frame sizes. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new ParameterShrinker(methodRemovalParameterCounter)))); |
| } |
| else if (codeRemovalAdvanced) |
| { |
| // Just update the local variable frame sizes. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new StackSizeUpdater()))); |
| } |
| |
| // // Specializing the class member descriptors seems to increase the |
| // // class file size, on average. |
| // // Specialize all class member descriptors. |
| // programClassPool.classesAccept(new AllMemberVisitor( |
| // new OptimizationInfoMemberFilter( |
| // new MemberDescriptorSpecializer()))); |
| // |
| // // Fix all references to classes, for MemberDescriptorSpecializer. |
| // programClassPool.classesAccept(new AllMemberVisitor( |
| // new OptimizationInfoMemberFilter( |
| // new ClassReferenceFixer(true)))); |
| |
| // Mark all classes with package visible members. |
| // Mark all exception catches of methods. |
| // Count all method invocations. |
| // Mark super invocations and other access of methods. |
| programClassPool.classesAccept( |
| new MultiClassVisitor( |
| new ClassVisitor[] |
| { |
| new AllConstantVisitor( |
| new PackageVisibleMemberInvokingClassMarker()), |
| new AllMethodVisitor( |
| new MultiMemberVisitor( |
| new MemberVisitor[] |
| { |
| new PackageVisibleMemberContainingClassMarker(), |
| new AllAttributeVisitor( |
| new MultiAttributeVisitor( |
| new AttributeVisitor[] |
| { |
| new CatchExceptionMarker(), |
| new AllInstructionVisitor( |
| new MultiInstructionVisitor( |
| new InstructionVisitor[] |
| { |
| new InstantiationClassMarker(), |
| new InstanceofClassMarker(), |
| new DotClassMarker(), |
| new MethodInvocationMarker(), |
| new SuperInvocationMarker(), |
| new BackwardBranchMarker(), |
| new AccessMethodMarker(), |
| })), |
| new AllExceptionInfoVisitor( |
| new ExceptionHandlerConstantVisitor( |
| new ReferencedClassVisitor( |
| new CaughtClassMarker()))), |
| })), |
| })), |
| })); |
| |
| if (classMergingVertical) |
| { |
| // Merge classes into their superclasses or interfaces. |
| programClassPool.classesAccept( |
| new VerticalClassMerger(configuration.allowAccessModification, |
| configuration.mergeInterfacesAggressively, |
| classMergingVerticalCounter)); |
| } |
| |
| if (classMergingHorizontal) |
| { |
| // Merge classes into their sibling classes. |
| programClassPool.classesAccept( |
| new HorizontalClassMerger(configuration.allowAccessModification, |
| configuration.mergeInterfacesAggressively, |
| classMergingHorizontalCounter)); |
| } |
| |
| if (classMergingVertical || |
| classMergingHorizontal) |
| { |
| // Clean up inner class attributes to avoid loops. |
| programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover()); |
| |
| // Update references to merged classes. |
| programClassPool.classesAccept(new TargetClassChanger()); |
| programClassPool.classesAccept(new ClassReferenceFixer(true)); |
| programClassPool.classesAccept(new MemberReferenceFixer()); |
| |
| if (configuration.allowAccessModification) |
| { |
| // Fix the access flags of referenced merged classes and their |
| // class members. |
| programClassPool.classesAccept( |
| new AllConstantVisitor( |
| new AccessFixer())); |
| } |
| } |
| |
| if (methodRemovalParameter || |
| classMergingVertical || |
| classMergingHorizontal) |
| { |
| // Tweak the descriptors of duplicate initializers. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new DuplicateInitializerFixer(initializerFixCounter))); |
| |
| if (initializerFixCounter.getCount() > 0) |
| { |
| // Fix all invocations of tweaked initializers. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new DuplicateInitializerInvocationFixer(addedCounter)))); |
| |
| // Fix all references to tweaked initializers. |
| programClassPool.classesAccept(new MemberReferenceFixer()); |
| } |
| } |
| |
| if (methodInliningUnique) |
| { |
| // Inline methods that are only invoked once. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new MethodInliner(configuration.microEdition, |
| configuration.allowAccessModification, |
| true, |
| methodInliningUniqueCounter)))); |
| } |
| |
| if (methodInliningShort) |
| { |
| // Inline short methods. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new MethodInliner(configuration.microEdition, |
| configuration.allowAccessModification, |
| false, |
| methodInliningShortCounter)))); |
| } |
| |
| if (methodInliningTailrecursion) |
| { |
| // Simplify tail recursion calls. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new TailRecursionSimplifier(methodInliningTailrecursionCounter)))); |
| } |
| |
| if (fieldMarkingPrivate || |
| methodMarkingPrivate) |
| { |
| // Mark all class members that can not be made private. |
| programClassPool.classesAccept( |
| new NonPrivateMemberMarker()); |
| } |
| |
| if (fieldMarkingPrivate || |
| methodMarkingPrivate) |
| { |
| // Make all non-private fields private, whereever possible. |
| programClassPool.classesAccept( |
| new AllFieldVisitor( |
| new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, |
| new MemberPrivatizer(fieldMarkingPrivateCounter)))); |
| } |
| |
| if (methodMarkingPrivate) |
| { |
| // Make all non-private methods private, whereever possible. |
| programClassPool.classesAccept( |
| new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE, |
| new AllMethodVisitor( |
| new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, |
| new MemberPrivatizer(methodMarkingPrivateCounter))))); |
| } |
| |
| if ((methodInliningUnique || |
| methodInliningShort || |
| methodInliningTailrecursion) && |
| configuration.allowAccessModification) |
| { |
| // Fix the access flags of referenced classes and class members, |
| // for MethodInliner. |
| programClassPool.classesAccept( |
| new AllConstantVisitor( |
| new AccessFixer())); |
| } |
| |
| if (methodRemovalParameter || |
| classMergingVertical || |
| classMergingHorizontal || |
| methodMarkingPrivate) |
| { |
| // Fix invocations of interface methods, of methods that have become |
| // non-abstract or private, and of methods that have moved to a |
| // different package. |
| programClassPool.classesAccept( |
| new AllMemberVisitor( |
| new AllAttributeVisitor( |
| new MethodInvocationFixer()))); |
| } |
| |
| if (codeMerging) |
| { |
| // Share common blocks of code at branches. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new GotoCommonCodeReplacer(codeMergingCounter)))); |
| } |
| |
| // Create a branch target marker and a code attribute editor that can |
| // be reused for all code attributes. |
| BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); |
| CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); |
| |
| List peepholeOptimizations = new ArrayList(); |
| if (codeSimplificationVariable) |
| { |
| // Peephole optimizations involving local variables. |
| peepholeOptimizations.add( |
| new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, |
| InstructionSequenceConstants.VARIABLE, |
| branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter)); |
| } |
| |
| if (codeSimplificationArithmetic) |
| { |
| // Peephole optimizations involving arithmetic operations. |
| peepholeOptimizations.add( |
| new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, |
| InstructionSequenceConstants.ARITHMETIC, |
| branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter)); |
| } |
| |
| if (codeSimplificationCast) |
| { |
| // Peephole optimizations involving cast operations. |
| peepholeOptimizations.add( |
| new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, |
| InstructionSequenceConstants.CAST, |
| branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter)); |
| } |
| |
| if (codeSimplificationField) |
| { |
| // Peephole optimizations involving fields. |
| peepholeOptimizations.add( |
| new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, |
| InstructionSequenceConstants.FIELD, |
| branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter)); |
| } |
| |
| if (codeSimplificationBranch) |
| { |
| // Peephole optimizations involving branches. |
| peepholeOptimizations.add( |
| new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, |
| InstructionSequenceConstants.BRANCH, |
| branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter)); |
| |
| // Include optimization of branches to branches and returns. |
| peepholeOptimizations.add( |
| new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); |
| peepholeOptimizations.add( |
| new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); |
| } |
| |
| if (!peepholeOptimizations.isEmpty()) |
| { |
| // Convert the list into an array. |
| InstructionVisitor[] peepholeOptimizationsArray = |
| new InstructionVisitor[peepholeOptimizations.size()]; |
| peepholeOptimizations.toArray(peepholeOptimizationsArray); |
| |
| // Perform the peephole optimisations. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor, |
| new MultiInstructionVisitor( |
| peepholeOptimizationsArray))))); |
| } |
| |
| if (codeRemovalException) |
| { |
| // Remove unnecessary exception handlers. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new UnreachableExceptionRemover(codeRemovalExceptionCounter)))); |
| } |
| |
| if (codeRemovalSimple) |
| { |
| // Remove unreachable code. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new UnreachableCodeRemover(deletedCounter)))); |
| } |
| |
| if (codeRemovalVariable) |
| { |
| // Remove all unused local variables. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new VariableShrinker(codeRemovalVariableCounter)))); |
| } |
| else |
| { |
| // Clean up all unused local variables. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new VariableCleaner()))); |
| } |
| |
| if (codeAllocationVariable) |
| { |
| // Optimize the variables. |
| programClassPool.classesAccept( |
| new AllMethodVisitor( |
| new AllAttributeVisitor( |
| new VariableOptimizer(false, codeAllocationVariableCounter)))); |
| } |
| |
| int classMarkingFinalCount = classMarkingFinalCounter .getCount(); |
| int classMergingVerticalCount = classMergingVerticalCounter .getCount(); |
| int classMergingHorizontalCount = classMergingHorizontalCounter .getCount(); |
| int fieldRemovalWriteonlyCount = fieldRemovalWriteonlyCounter .getCount(); |
| int fieldMarkingPrivateCount = fieldMarkingPrivateCounter .getCount(); |
| int fieldPropagationValueCount = fieldPropagationValueCounter .getCount(); |
| int methodMarkingPrivateCount = methodMarkingPrivateCounter .getCount(); |
| int methodMarkingStaticCount = methodMarkingStaticCounter .getCount(); |
| int methodMarkingFinalCount = methodMarkingFinalCounter .getCount(); |
| int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter.getCount(); |
| int methodPropagationParameterCount = methodPropagationParameterCounter .getCount(); |
| int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount(); |
| int methodInliningShortCount = methodInliningShortCounter .getCount(); |
| int methodInliningUniqueCount = methodInliningUniqueCounter .getCount(); |
| int methodInliningTailrecursionCount = methodInliningTailrecursionCounter .getCount(); |
| int codeMergingCount = codeMergingCounter .getCount(); |
| int codeSimplificationVariableCount = codeSimplificationVariableCounter .getCount(); |
| int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter.getCount(); |
| int codeSimplificationCastCount = codeSimplificationCastCounter .getCount(); |
| int codeSimplificationFieldCount = codeSimplificationFieldCounter .getCount(); |
| int codeSimplificationBranchCount = codeSimplificationBranchCounter .getCount(); |
| int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter .getCount(); |
| int codeRemovalCount = deletedCounter .getCount() - addedCounter.getCount(); |
| int codeRemovalVariableCount = codeRemovalVariableCounter .getCount(); |
| int codeRemovalExceptionCount = codeRemovalExceptionCounter .getCount(); |
| int codeAllocationVariableCount = codeAllocationVariableCounter .getCount(); |
| |
| if (configuration.verbose) |
| { |
| System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal)); |
| System.out.println(" Number of vertically merged classes: " + classMergingVerticalCount + disabled(classMergingVertical)); |
| System.out.println(" Number of horizontally merged classes: " + classMergingHorizontalCount + disabled(classMergingHorizontal)); |
| System.out.println(" Number of removed write-only fields: " + fieldRemovalWriteonlyCount + disabled(fieldRemovalWriteonly)); |
| System.out.println(" Number of privatized fields: " + fieldMarkingPrivateCount + disabled(fieldMarkingPrivate)); |
| System.out.println(" Number of inlined constant fields: " + fieldPropagationValueCount + disabled(fieldPropagationValue)); |
| System.out.println(" Number of privatized methods: " + methodMarkingPrivateCount + disabled(methodMarkingPrivate)); |
| System.out.println(" Number of staticized methods: " + methodMarkingStaticCount + disabled(methodMarkingStatic)); |
| System.out.println(" Number of finalized methods: " + methodMarkingFinalCount + disabled(methodMarkingFinal)); |
| System.out.println(" Number of removed method parameters: " + methodRemovalParameterCount + disabled(methodRemovalParameter)); |
| System.out.println(" Number of inlined constant parameters: " + methodPropagationParameterCount + disabled(methodPropagationParameter)); |
| System.out.println(" Number of inlined constant return values: " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue)); |
| System.out.println(" Number of inlined short method calls: " + methodInliningShortCount + disabled(methodInliningShort)); |
| System.out.println(" Number of inlined unique method calls: " + methodInliningUniqueCount + disabled(methodInliningUnique)); |
| System.out.println(" Number of inlined tail recursion calls: " + methodInliningTailrecursionCount + disabled(methodInliningTailrecursion)); |
| System.out.println(" Number of merged code blocks: " + codeMergingCount + disabled(codeMerging)); |
| System.out.println(" Number of variable peephole optimizations: " + codeSimplificationVariableCount + disabled(codeSimplificationVariable)); |
| System.out.println(" Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic)); |
| System.out.println(" Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast)); |
| System.out.println(" Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField)); |
| System.out.println(" Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch)); |
| System.out.println(" Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced)); |
| System.out.println(" Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced)); |
| System.out.println(" Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable)); |
| System.out.println(" Number of removed exception blocks: " + codeRemovalExceptionCount + disabled(codeRemovalException)); |
| System.out.println(" Number of optimized local variable frames: " + codeAllocationVariableCount + disabled(codeAllocationVariable)); |
| } |
| |
| return classMarkingFinalCount > 0 || |
| classMergingVerticalCount > 0 || |
| classMergingHorizontalCount > 0 || |
| fieldRemovalWriteonlyCount > 0 || |
| fieldMarkingPrivateCount > 0 || |
| methodMarkingPrivateCount > 0 || |
| methodMarkingStaticCount > 0 || |
| methodMarkingFinalCount > 0 || |
| fieldPropagationValueCount > 0 || |
| methodRemovalParameterCount > 0 || |
| methodPropagationParameterCount > 0 || |
| methodPropagationReturnvalueCount > 0 || |
| methodInliningShortCount > 0 || |
| methodInliningUniqueCount > 0 || |
| methodInliningTailrecursionCount > 0 || |
| codeMergingCount > 0 || |
| codeSimplificationVariableCount > 0 || |
| codeSimplificationArithmeticCount > 0 || |
| codeSimplificationCastCount > 0 || |
| codeSimplificationFieldCount > 0 || |
| codeSimplificationBranchCount > 0 || |
| codeSimplificationAdvancedCount > 0 || |
| codeRemovalCount > 0 || |
| codeRemovalVariableCount > 0 || |
| codeRemovalExceptionCount > 0 || |
| codeAllocationVariableCount > 0; |
| } |
| |
| |
| /** |
| * Returns a String indicating whether the given flag is enabled or |
| * disabled. |
| */ |
| private String disabled(boolean flag) |
| { |
| return flag ? "" : " (disabled)"; |
| } |
| |
| |
| /** |
| * Returns a String indicating whether the given flags are enabled or |
| * disabled. |
| */ |
| private String disabled(boolean flag1, boolean flag2) |
| { |
| return flag1 && flag2 ? "" : |
| flag1 || flag2 ? " (partially disabled)" : |
| " (disabled)"; |
| } |
| } |