/* * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * * Copyright (c) 2002-2010 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_MARKING_PRIVATE, 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())); } // Fix the access flags of the inner classes information. programClassPool.classesAccept( new AllAttributeVisitor( new AllInnerClassesInfoVisitor( new InnerClassesAccessFixer()))); } 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) { // Make all non-private fields private, whereever possible. programClassPool.classesAccept( new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE, 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)))); } 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)"; } }