blob: a3e8a6ef1f1a787e174cf744fd5f12ac5ddd0e1d [file] [log] [blame]
/*
* 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)";
}
}