aboutsummaryrefslogtreecommitdiffstats
path: root/src/proguard/optimize/Optimizer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/optimize/Optimizer.java')
-rw-r--r--src/proguard/optimize/Optimizer.java876
1 files changed, 876 insertions, 0 deletions
diff --git a/src/proguard/optimize/Optimizer.java b/src/proguard/optimize/Optimizer.java
new file mode 100644
index 0000000..a3e8a6e
--- /dev/null
+++ b/src/proguard/optimize/Optimizer.java
@@ -0,0 +1,876 @@
+/*
+ * 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)";
+ }
+}