KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > optimize > Optimizer


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  *
13  * This program is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16  * more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21  */

22 package proguard.optimize;
23
24 import proguard.*;
25 import proguard.evaluation.value.SpecificValueFactory;
26 import proguard.classfile.*;
27 import proguard.classfile.attribute.visitor.*;
28 import proguard.classfile.constant.visitor.AllConstantVisitor;
29 import proguard.classfile.editor.*;
30 import proguard.classfile.instruction.visitor.*;
31 import proguard.classfile.util.MethodLinker;
32 import proguard.classfile.visitor.*;
33 import proguard.optimize.evaluation.*;
34 import proguard.optimize.peephole.*;
35 import proguard.optimize.info.*;
36
37 import java.io.IOException JavaDoc;
38
39 /**
40  * This class optimizes class pools according to a given configuration.
41  *
42  * @author Eric Lafortune
43  */

44 public class Optimizer
45 {
46     private Configuration configuration;
47
48
49     /**
50      * Creates a new Optimizer.
51      */

52     public Optimizer(Configuration configuration)
53     {
54         this.configuration = configuration;
55     }
56
57
58     /**
59      * Performs optimization of the given program class pool.
60      */

61     public boolean execute(ClassPool programClassPool,
62                            ClassPool libraryClassPool) throws IOException JavaDoc
63     {
64         // Check if we have at least some keep commands.
65
if (configuration.keep == null &&
66             configuration.applyMapping == null &&
67             configuration.printMapping == null)
68         {
69             throw new IOException JavaDoc("You have to specify '-keep' options for the optimization step.");
70         }
71
72         // Create counters to count the numbers of optimizations.
73
ClassCounter singleImplementationCounter = new ClassCounter();
74         ClassCounter finalClassCounter = new ClassCounter();
75         MemberCounter finalMethodCounter = new MemberCounter();
76         MemberCounter privateFieldCounter = new MemberCounter();
77         MemberCounter privateMethodCounter = new MemberCounter();
78         MemberCounter staticMethodCounter = new MemberCounter();
79         MemberCounter writeOnlyFieldCounter = new MemberCounter();
80         MemberCounter constantFieldCounter = new MemberCounter();
81         MemberCounter constantMethodCounter = new MemberCounter();
82         MemberCounter descriptorShrinkCounter = new MemberCounter();
83         MemberCounter parameterShrinkCounter = new MemberCounter();
84         MemberCounter variableShrinkCounter = new MemberCounter();
85         ExceptionCounter exceptionCounter = new ExceptionCounter();
86         InstructionCounter inliningCounter = new InstructionCounter();
87         InstructionCounter commonCodeCounter = new InstructionCounter();
88         InstructionCounter pushCounter = new InstructionCounter();
89         InstructionCounter branchCounter = new InstructionCounter();
90         InstructionCounter deletedCounter = new InstructionCounter();
91         InstructionCounter addedCounter = new InstructionCounter();
92         InstructionCounter peepholeCounter = new InstructionCounter();
93
94         // Clean up any old visitor info.
95
programClassPool.classesAccept(new ClassCleaner());
96         libraryClassPool.classesAccept(new ClassCleaner());
97
98         // Link all methods that should get the same optimization info.
99
programClassPool.classesAccept(new BottomClassFilter(
100                                        new MethodLinker()));
101         libraryClassPool.classesAccept(new BottomClassFilter(
102                                        new MethodLinker()));
103
104         // Create a visitor for marking the seeds.
105
KeepMarker keepMarker = new KeepMarker();
106         ClassPoolVisitor classPoolvisitor =
107             ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep,
108                                                                     keepMarker,
109                                                                     keepMarker,
110                                                                     false,
111                                                                     true,
112                                                                     false);
113         // Mark the seeds.
114
programClassPool.accept(classPoolvisitor);
115         libraryClassPool.accept(classPoolvisitor);
116
117         // All library classes and library class members remain unchanged.
118
libraryClassPool.classesAccept(keepMarker);
119         libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker));
120
121         // We also keep all classes that are involved in .class constructs.
122
programClassPool.classesAccept(new AllMethodVisitor(
123                                        new AllAttributeVisitor(
124                                        new AllInstructionVisitor(
125                                        new DotClassClassVisitor(keepMarker)))));
126
127         // We also keep all classes that are involved in Class.forName constructs.
128
programClassPool.classesAccept(new AllConstantVisitor(
129                                        new ClassForNameClassVisitor(keepMarker)));
130
131         // Attach some optimization info to all class members, so it can be
132
// filled out later.
133
programClassPool.classesAccept(new AllMemberVisitor(
134                                        new MemberOptimizationInfoSetter()));
135
136         if (configuration.assumeNoSideEffects != null)
137         {
138             // Create a visitor for marking methods that don't have any side effects.
139
NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker();
140             ClassPoolVisitor noClassPoolvisitor =
141                 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects,
142                                                                         null,
143                                                                         noSideEffectMethodMarker);
144
145             // Mark the seeds.
146
programClassPool.accept(noClassPoolvisitor);
147             libraryClassPool.accept(noClassPoolvisitor);
148         }
149
150         // Mark all interfaces that have single implementations.
151
programClassPool.classesAccept(new SingleImplementationMarker(configuration.allowAccessModification, singleImplementationCounter));
152
153         // Make classes and methods final, as far as possible.
154
programClassPool.classesAccept(new ClassFinalizer(finalClassCounter, finalMethodCounter));
155
156         // Mark all fields that are write-only.
157
programClassPool.classesAccept(new AllMethodVisitor(
158                                        new AllAttributeVisitor(
159                                        new AllInstructionVisitor(
160                                        new MultiInstructionVisitor(
161                                        new InstructionVisitor[]
162                                        {
163                                            new ReadWriteFieldMarker(),
164                                        })))));
165
166         // Mark all used parameters, including the 'this' parameters.
167
programClassPool.classesAccept(new AllMethodVisitor(
168                                        new OptimizationInfoMemberFilter(
169                                        new ParameterUsageMarker())));
170
171         // Shrink the parameters in the method descriptors.
172
programClassPool.classesAccept(new AllMethodVisitor(
173                                        new OptimizationInfoMemberFilter(
174                                        new MethodDescriptorShrinker(descriptorShrinkCounter))));
175
176         // Make all non-static methods that don't require the 'this' parameter static.
177
programClassPool.classesAccept(new AllMethodVisitor(
178                                        new OptimizationInfoMemberFilter(
179                                        new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC,
180                                        new MethodStaticizer(staticMethodCounter)))));
181
182         // Remove all unused parameters and variables from the code, for
183
// MethodDescriptorShrinker, MethodStaticizer.
184
programClassPool.classesAccept(new AllMethodVisitor(
185                                        new AllAttributeVisitor(
186                                        new ParameterShrinker(parameterShrinkCounter))));
187
188         // Fix invocations of methods that have become static, for
189
// MethodStaticizer.
190
programClassPool.classesAccept(new AllMethodVisitor(
191                                        new AllAttributeVisitor(
192                                        new MethodInvocationFixer())));
193
194         // Fix all references to class members, for MethodDescriptorShrinker.
195
programClassPool.classesAccept(new MemberReferenceFixer());
196
197         // Mark all methods that have side effects.
198
programClassPool.accept(new SideEffectMethodMarker());
199
200 // System.out.println("Optimizer.execute: before evaluation simplification");
201
// programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter()));
202

203         // Perform partial evaluation for filling out fields, method parameters,
204
// and method return values.
205
programClassPool.classesAccept(new AllMethodVisitor(
206                                        new AllAttributeVisitor(
207                                        new PartialEvaluator(new SpecificValueFactory(), new UnusedParameterInvocationUnit(new StoringInvocationUnit()), false))));
208
209         // Count the write-only fields, and the constant fields and methods.
210
programClassPool.classesAccept(new MultiClassVisitor(
211                                        new ClassVisitor[]
212                                        {
213                                            new AllFieldVisitor(
214                                            new WriteOnlyFieldFilter(writeOnlyFieldCounter)),
215                                            new AllFieldVisitor(
216                                            new ConstantMemberFilter(constantFieldCounter)),
217                                            new AllMethodVisitor(
218                                            new ConstantMemberFilter(constantMethodCounter)),
219                                        }));
220
221         // Simplify based on partial evaluation.
222
// Also remove unused parameters from the stack before method invocations,
223
// for MethodDescriptorShrinker, MethodStaticizer.
224
programClassPool.classesAccept(new AllMethodVisitor(
225                                        new AllAttributeVisitor(
226                                        new EvaluationSimplifier(
227                                        new PartialEvaluator(new SpecificValueFactory(), new UnusedParameterInvocationUnit(new LoadingInvocationUnit()), false),
228                                        pushCounter, branchCounter, deletedCounter, addedCounter))));
229
230 // // Specializing the class member descriptors seems to increase the
231
// // class file size, on average.
232
// // Specialize all class member descriptors.
233
// programClassPool.classesAccept(new AllMemberVisitor(
234
// new OptimizationInfoMemberFilter(
235
// new MemberDescriptorSpecializer())));
236
//
237
// // Fix all references to classes, for MemberDescriptorSpecializer.
238
// programClassPool.classesAccept(new AllMemberVisitor(
239
// new OptimizationInfoMemberFilter(
240
// new ClassReferenceFixer(true))));
241

242         // Inline interfaces with single implementations.
243
programClassPool.classesAccept(new SingleImplementationInliner());
244
245         // Restore the interface references from these single implementations.
246
programClassPool.classesAccept(new SingleImplementationFixer());
247
248         if (configuration.allowAccessModification)
249         {
250             // Fix the access flags of referenced classes and class members,
251
// for SingleImplementationInliner.
252
programClassPool.classesAccept(new AllConstantVisitor(
253                                            new AccessFixer()));
254         }
255
256         // Fix all references to classes, for SingleImplementationInliner.
257
programClassPool.classesAccept(new ClassReferenceFixer(true));
258
259         // Fix all references to class members, for SingleImplementationInliner.
260
programClassPool.classesAccept(new MemberReferenceFixer());
261
262         // Count all method invocations.
263
// Mark super invocations and other access of methods.
264
// Mark all exception catches of methods.
265
programClassPool.classesAccept(new AllMethodVisitor(
266                                        new AllAttributeVisitor(
267                                        new MultiAttributeVisitor(
268                                        new AttributeVisitor[]
269                                        {
270                                            new AllInstructionVisitor(
271                                            new MultiInstructionVisitor(
272                                            new InstructionVisitor[]
273                                            {
274                                                new MethodInvocationMarker(),
275                                                new SuperInvocationMarker(),
276                                                new BackwardBranchMarker(),
277                                                new AccessMethodMarker(),
278                                            })),
279                                            new CatchExceptionMarker(),
280                                        }))));
281
282         // Inline methods that are only invoked once.
283
programClassPool.classesAccept(new AllMethodVisitor(
284                                        new AllAttributeVisitor(
285                                        new MethodInliner(configuration.allowAccessModification, true, inliningCounter))));
286
287         // Inline short methods.
288
programClassPool.classesAccept(new AllMethodVisitor(
289                                        new AllAttributeVisitor(
290                                        new MethodInliner(configuration.allowAccessModification, false, inliningCounter))));
291
292         // Mark all class members that can not be made private.
293
programClassPool.classesAccept(new NonPrivateMemberMarker());
294
295         // Make all non-private and unmarked class members in non-interface
296
// classes private.
297
programClassPool.classesAccept(new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE,
298                                        new AllMemberVisitor(
299                                        new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE,
300                                        new MemberPrivatizer(privateFieldCounter, privateMethodCounter)))));
301
302         if (configuration.allowAccessModification)
303         {
304             // Fix the access flags of referenced classes and class members,
305
// for MethodInliner.
306
programClassPool.classesAccept(new AllConstantVisitor(
307                                            new AccessFixer()));
308         }
309
310         // Fix invocations of methods that have become non-abstract or private,
311
// for SingleImplementationInliner, MemberPrivatizer, AccessFixer.
312
programClassPool.classesAccept(new AllMemberVisitor(
313                                        new AllAttributeVisitor(
314                                        new MethodInvocationFixer())));
315
316         // Create a branch target marker and a code attribute editor that can
317
// be reused for all code attributes.
318
BranchTargetFinder branchTargetFinder = new BranchTargetFinder();
319         CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor();
320
321         // Share common blocks of code at branches.
322
programClassPool.classesAccept(new AllMethodVisitor(
323                                        new AllAttributeVisitor(
324                                        new GotoCommonCodeReplacer(commonCodeCounter))));
325
326         // Perform various peephole optimisations.
327
programClassPool.classesAccept(new AllMethodVisitor(
328                                        new AllAttributeVisitor(
329                                        new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor,
330                                        new MultiInstructionVisitor(
331                                        new InstructionVisitor[]
332                                        {
333                                            new InstructionSequencesReplacer(InstructionSequenceConstants.PATTERN_CONSTANTS,
334                                                                             InstructionSequenceConstants.INSTRUCTION_SEQUENCES,
335                                                                             branchTargetFinder, codeAttributeEditor, peepholeCounter),
336                                            new GotoGotoReplacer( codeAttributeEditor, peepholeCounter),
337                                            new GotoReturnReplacer( codeAttributeEditor, peepholeCounter),
338                                        })))));
339
340         // Remove unnecessary exception handlers.
341
programClassPool.classesAccept(new AllMethodVisitor(
342                                        new AllAttributeVisitor(
343                                        new UnreachableExceptionRemover(exceptionCounter))));
344
345         // Remove unreachable code.
346
programClassPool.classesAccept(new AllMethodVisitor(
347                                        new AllAttributeVisitor(
348                                        new UnreachableCodeRemover(deletedCounter))));
349
350         // Remove all unused local variables.
351
programClassPool.classesAccept(new AllMethodVisitor(
352                                        new AllAttributeVisitor(
353                                        new VariableShrinker(variableShrinkCounter))));
354
355         // Optimize the variables.
356
programClassPool.classesAccept(new AllMethodVisitor(
357                                        new AllAttributeVisitor(
358                                        new VariableOptimizer())));
359
360         int singleImplementationCount = singleImplementationCounter.getCount();
361         int finalClassCount = finalClassCounter .getCount();
362         int privateFieldCount = privateFieldCounter .getCount();
363         int privateMethodCount = privateMethodCounter .getCount();
364         int staticMethodCount = staticMethodCounter .getCount();
365         int finalMethodCount = finalMethodCounter .getCount();
366         int writeOnlyFieldCount = writeOnlyFieldCounter .getCount();
367         int constantFieldCount = constantFieldCounter .getCount();
368         int constantMethodCount = constantMethodCounter .getCount();
369         int descriptorShrinkCount = descriptorShrinkCounter .getCount();
370         int parameterShrinkCount = parameterShrinkCounter .getCount();
371         int variableShrinkCount = variableShrinkCounter .getCount();
372         int exceptionCount = exceptionCounter .getCount();
373         int inliningCount = inliningCounter .getCount();
374         int commonCodeCount = commonCodeCounter .getCount();
375         int pushCount = pushCounter .getCount();
376         int branchCount = branchCounter .getCount();
377         int removedCount = deletedCounter .getCount() - addedCounter.getCount();
378         int peepholeCount = peepholeCounter .getCount();
379
380         if (configuration.verbose)
381         {
382             System.out.println(" Number of inlined interfaces: "+singleImplementationCount);
383             System.out.println(" Number of finalized classes: "+finalClassCount);
384             System.out.println(" Number of privatized fields: "+privateFieldCount);
385             System.out.println(" Number of privatized methods: "+privateMethodCount);
386             System.out.println(" Number of staticized methods: "+staticMethodCount);
387             System.out.println(" Number of finalized methods: "+finalMethodCount);
388             System.out.println(" Number of removed write-only fields: "+writeOnlyFieldCount);
389             System.out.println(" Number of inlined constant fields: "+constantFieldCount);
390             System.out.println(" Number of inlined constant methods: "+constantMethodCount);
391             System.out.println(" Number of simplified method declarations: "+descriptorShrinkCount);
392             System.out.println(" Number of removed parameters: "+parameterShrinkCount);
393             System.out.println(" Number of removed local variables: "+variableShrinkCount);
394             System.out.println(" Number of inlined method calls: "+inliningCount);
395             System.out.println(" Number of removed exception blocks: "+exceptionCount);
396             System.out.println(" Number of merged code blocks: "+commonCodeCount);
397             System.out.println(" Number of simplified push instructions: "+pushCount);
398             System.out.println(" Number of simplified branches: "+branchCount);
399             System.out.println(" Number of removed instructions: "+removedCount);
400             System.out.println(" Number of peephole optimizations: "+peepholeCount);
401         }
402
403         return singleImplementationCount > 0 ||
404                finalClassCount > 0 ||
405                privateFieldCount > 0 ||
406                privateMethodCount > 0 ||
407                staticMethodCount > 0 ||
408                finalMethodCount > 0 ||
409                writeOnlyFieldCount > 0 ||
410                constantFieldCount > 0 ||
411                constantMethodCount > 0 ||
412                descriptorShrinkCount > 0 ||
413                parameterShrinkCount > 0 ||
414                variableShrinkCount > 0 ||
415                inliningCount > 0 ||
416                exceptionCount > 0 ||
417                commonCodeCount > 0 ||
418                pushCount > 0 ||
419                branchCount > 0 ||
420                removedCount > 0 ||
421                peepholeCount > 0;
422     }
423 }
424
Popular Tags