1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 Eric Lafortune (eric (at) 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 * This program is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 15 * more details. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write to the Free Software Foundation, Inc., 19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 */ 21 package proguard.optimize; 22 23 import proguard.*; 24 import proguard.classfile.*; 25 import proguard.classfile.attribute.visitor.*; 26 import proguard.classfile.constant.visitor.AllConstantVisitor; 27 import proguard.classfile.editor.*; 28 import proguard.classfile.instruction.visitor.*; 29 import proguard.classfile.util.MethodLinker; 30 import proguard.classfile.visitor.*; 31 import proguard.evaluation.*; 32 import proguard.evaluation.value.*; 33 import proguard.optimize.evaluation.*; 34 import proguard.optimize.info.*; 35 import proguard.optimize.peephole.*; 36 import proguard.util.*; 37 38 import java.io.IOException; 39 import java.util.*; 40 41 /** 42 * This class optimizes class pools according to a given configuration. 43 * 44 * @author Eric Lafortune 45 */ 46 public class Optimizer 47 { 48 private static final String CLASS_MARKING_FINAL = "class/marking/final"; 49 private static final String CLASS_MERGING_VERTICAL = "class/merging/vertical"; 50 private static final String CLASS_MERGING_HORIZONTAL = "class/merging/horizontal"; 51 private static final String FIELD_REMOVAL_WRITEONLY = "field/removal/writeonly"; 52 private static final String FIELD_MARKING_PRIVATE = "field/marking/private"; 53 private static final String FIELD_PROPAGATION_VALUE = "field/propagation/value"; 54 private static final String METHOD_MARKING_PRIVATE = "method/marking/private"; 55 private static final String METHOD_MARKING_STATIC = "method/marking/static"; 56 private static final String METHOD_MARKING_FINAL = "method/marking/final"; 57 private static final String METHOD_REMOVAL_PARAMETER = "method/removal/parameter"; 58 private static final String METHOD_PROPAGATION_PARAMETER = "method/propagation/parameter"; 59 private static final String METHOD_PROPAGATION_RETURNVALUE = "method/propagation/returnvalue"; 60 private static final String METHOD_INLINING_SHORT = "method/inlining/short"; 61 private static final String METHOD_INLINING_UNIQUE = "method/inlining/unique"; 62 private static final String METHOD_INLINING_TAILRECURSION = "method/inlining/tailrecursion"; 63 private static final String CODE_MERGING = "code/merging"; 64 private static final String CODE_SIMPLIFICATION_VARIABLE = "code/simplification/variable"; 65 private static final String CODE_SIMPLIFICATION_ARITHMETIC = "code/simplification/arithmetic"; 66 private static final String CODE_SIMPLIFICATION_CAST = "code/simplification/cast"; 67 private static final String CODE_SIMPLIFICATION_FIELD = "code/simplification/field"; 68 private static final String CODE_SIMPLIFICATION_BRANCH = "code/simplification/branch"; 69 private static final String CODE_SIMPLIFICATION_ADVANCED = "code/simplification/advanced"; 70 private static final String CODE_REMOVAL_ADVANCED = "code/removal/advanced"; 71 private static final String CODE_REMOVAL_SIMPLE = "code/removal/simple"; 72 private static final String CODE_REMOVAL_VARIABLE = "code/removal/variable"; 73 private static final String CODE_REMOVAL_EXCEPTION = "code/removal/exception"; 74 private static final String CODE_ALLOCATION_VARIABLE = "code/allocation/variable"; 75 76 77 public static final String[] OPTIMIZATION_NAMES = new String[] 78 { 79 CLASS_MARKING_FINAL, 80 CLASS_MERGING_VERTICAL, 81 CLASS_MERGING_HORIZONTAL, 82 FIELD_REMOVAL_WRITEONLY, 83 FIELD_PROPAGATION_VALUE, 84 METHOD_MARKING_PRIVATE, 85 METHOD_MARKING_STATIC, 86 METHOD_MARKING_FINAL, 87 METHOD_REMOVAL_PARAMETER, 88 METHOD_PROPAGATION_PARAMETER, 89 METHOD_PROPAGATION_RETURNVALUE, 90 METHOD_INLINING_SHORT, 91 METHOD_INLINING_UNIQUE, 92 METHOD_INLINING_TAILRECURSION, 93 CODE_MERGING, 94 CODE_SIMPLIFICATION_VARIABLE, 95 CODE_SIMPLIFICATION_ARITHMETIC, 96 CODE_SIMPLIFICATION_CAST, 97 CODE_SIMPLIFICATION_FIELD, 98 CODE_SIMPLIFICATION_BRANCH, 99 CODE_SIMPLIFICATION_ADVANCED, 100 CODE_REMOVAL_ADVANCED, 101 CODE_REMOVAL_SIMPLE, 102 CODE_REMOVAL_VARIABLE, 103 CODE_REMOVAL_EXCEPTION, 104 CODE_ALLOCATION_VARIABLE, 105 }; 106 107 108 private final Configuration configuration; 109 110 111 /** 112 * Creates a new Optimizer. 113 */ 114 public Optimizer(Configuration configuration) 115 { 116 this.configuration = configuration; 117 } 118 119 120 /** 121 * Performs optimization of the given program class pool. 122 */ 123 public boolean execute(ClassPool programClassPool, 124 ClassPool libraryClassPool) throws IOException 125 { 126 // Check if we have at least some keep commands. 127 if (configuration.keep == null && 128 configuration.applyMapping == null && 129 configuration.printMapping == null) 130 { 131 throw new IOException("You have to specify '-keep' options for the optimization step."); 132 } 133 134 // Create a matcher for filtering optimizations. 135 StringMatcher filter = configuration.optimizations != null ? 136 new ListParser(new NameParser()).parse(configuration.optimizations) : 137 new ConstantMatcher(true); 138 139 boolean classMarkingFinal = filter.matches(CLASS_MARKING_FINAL); 140 boolean classMergingVertical = filter.matches(CLASS_MERGING_VERTICAL); 141 boolean classMergingHorizontal = filter.matches(CLASS_MERGING_HORIZONTAL); 142 boolean fieldRemovalWriteonly = filter.matches(FIELD_REMOVAL_WRITEONLY); 143 boolean fieldMarkingPrivate = filter.matches(FIELD_MARKING_PRIVATE); 144 boolean fieldPropagationValue = filter.matches(FIELD_PROPAGATION_VALUE); 145 boolean methodMarkingPrivate = filter.matches(METHOD_MARKING_PRIVATE); 146 boolean methodMarkingStatic = filter.matches(METHOD_MARKING_STATIC); 147 boolean methodMarkingFinal = filter.matches(METHOD_MARKING_FINAL); 148 boolean methodRemovalParameter = filter.matches(METHOD_REMOVAL_PARAMETER); 149 boolean methodPropagationParameter = filter.matches(METHOD_PROPAGATION_PARAMETER); 150 boolean methodPropagationReturnvalue = filter.matches(METHOD_PROPAGATION_RETURNVALUE); 151 boolean methodInliningShort = filter.matches(METHOD_INLINING_SHORT); 152 boolean methodInliningUnique = filter.matches(METHOD_INLINING_UNIQUE); 153 boolean methodInliningTailrecursion = filter.matches(METHOD_INLINING_TAILRECURSION); 154 boolean codeMerging = filter.matches(CODE_MERGING); 155 boolean codeSimplificationVariable = filter.matches(CODE_SIMPLIFICATION_VARIABLE); 156 boolean codeSimplificationArithmetic = filter.matches(CODE_SIMPLIFICATION_ARITHMETIC); 157 boolean codeSimplificationCast = filter.matches(CODE_SIMPLIFICATION_CAST); 158 boolean codeSimplificationField = filter.matches(CODE_SIMPLIFICATION_FIELD); 159 boolean codeSimplificationBranch = filter.matches(CODE_SIMPLIFICATION_BRANCH); 160 boolean codeSimplificationAdvanced = filter.matches(CODE_SIMPLIFICATION_ADVANCED); 161 boolean codeRemovalAdvanced = filter.matches(CODE_REMOVAL_ADVANCED); 162 boolean codeRemovalSimple = filter.matches(CODE_REMOVAL_SIMPLE); 163 boolean codeRemovalVariable = filter.matches(CODE_REMOVAL_VARIABLE); 164 boolean codeRemovalException = filter.matches(CODE_REMOVAL_EXCEPTION); 165 boolean codeAllocationVariable = filter.matches(CODE_ALLOCATION_VARIABLE); 166 167 // Create counters to count the numbers of optimizations. 168 ClassCounter classMarkingFinalCounter = new ClassCounter(); 169 ClassCounter classMergingVerticalCounter = new ClassCounter(); 170 ClassCounter classMergingHorizontalCounter = new ClassCounter(); 171 MemberCounter fieldRemovalWriteonlyCounter = new MemberCounter(); 172 MemberCounter fieldMarkingPrivateCounter = new MemberCounter(); 173 MemberCounter fieldPropagationValueCounter = new MemberCounter(); 174 MemberCounter methodMarkingPrivateCounter = new MemberCounter(); 175 MemberCounter methodMarkingStaticCounter = new MemberCounter(); 176 MemberCounter methodMarkingFinalCounter = new MemberCounter(); 177 MemberCounter methodRemovalParameterCounter = new MemberCounter(); 178 MemberCounter methodPropagationParameterCounter = new MemberCounter(); 179 MemberCounter methodPropagationReturnvalueCounter = new MemberCounter(); 180 InstructionCounter methodInliningShortCounter = new InstructionCounter(); 181 InstructionCounter methodInliningUniqueCounter = new InstructionCounter(); 182 InstructionCounter methodInliningTailrecursionCounter = new InstructionCounter(); 183 InstructionCounter codeMergingCounter = new InstructionCounter(); 184 InstructionCounter codeSimplificationVariableCounter = new InstructionCounter(); 185 InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter(); 186 InstructionCounter codeSimplificationCastCounter = new InstructionCounter(); 187 InstructionCounter codeSimplificationFieldCounter = new InstructionCounter(); 188 InstructionCounter codeSimplificationBranchCounter = new InstructionCounter(); 189 InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter(); 190 InstructionCounter deletedCounter = new InstructionCounter(); 191 InstructionCounter addedCounter = new InstructionCounter(); 192 MemberCounter codeRemovalVariableCounter = new MemberCounter(); 193 ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter(); 194 MemberCounter codeAllocationVariableCounter = new MemberCounter(); 195 MemberCounter initializerFixCounter = new MemberCounter(); 196 197 // Some optimizations are required by other optimizations. 198 codeSimplificationAdvanced = 199 codeSimplificationAdvanced || 200 fieldPropagationValue || 201 methodPropagationParameter || 202 methodPropagationReturnvalue; 203 204 codeRemovalAdvanced = 205 codeRemovalAdvanced || 206 fieldRemovalWriteonly || 207 methodMarkingStatic || 208 methodRemovalParameter; 209 210 codeRemovalSimple = 211 codeRemovalSimple || 212 codeSimplificationBranch; 213 214 codeRemovalException = 215 codeRemovalException || 216 codeRemovalAdvanced || 217 codeRemovalSimple; 218 219 // Clean up any old visitor info. 220 programClassPool.classesAccept(new ClassCleaner()); 221 libraryClassPool.classesAccept(new ClassCleaner()); 222 223 // Link all methods that should get the same optimization info. 224 programClassPool.classesAccept(new BottomClassFilter( 225 new MethodLinker())); 226 libraryClassPool.classesAccept(new BottomClassFilter( 227 new MethodLinker())); 228 229 // Create a visitor for marking the seeds. 230 KeepMarker keepMarker = new KeepMarker(); 231 ClassPoolVisitor classPoolvisitor = 232 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, 233 keepMarker, 234 keepMarker, 235 false, 236 true, 237 false); 238 // Mark the seeds. 239 programClassPool.accept(classPoolvisitor); 240 libraryClassPool.accept(classPoolvisitor); 241 242 // All library classes and library class members remain unchanged. 243 libraryClassPool.classesAccept(keepMarker); 244 libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker)); 245 246 // We also keep all classes that are involved in .class constructs. 247 programClassPool.classesAccept( 248 new AllMethodVisitor( 249 new AllAttributeVisitor( 250 new AllInstructionVisitor( 251 new DotClassClassVisitor(keepMarker))))); 252 253 // We also keep all classes that are involved in Class.forName constructs. 254 programClassPool.classesAccept( 255 new AllConstantVisitor( 256 new ClassForNameClassVisitor(keepMarker))); 257 258 // Attach some optimization info to all classes and class members, so 259 // it can be filled out later. 260 programClassPool.classesAccept(new ClassOptimizationInfoSetter()); 261 262 programClassPool.classesAccept(new AllMemberVisitor( 263 new MemberOptimizationInfoSetter())); 264 265 if (configuration.assumeNoSideEffects != null) 266 { 267 // Create a visitor for marking methods that don't have any side effects. 268 NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker(); 269 ClassPoolVisitor noClassPoolvisitor = 270 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects, 271 null, 272 noSideEffectMethodMarker); 273 274 // Mark the seeds. 275 programClassPool.accept(noClassPoolvisitor); 276 libraryClassPool.accept(noClassPoolvisitor); 277 } 278 279 if (classMarkingFinal) 280 { 281 // Make classes final, whereever possible. 282 programClassPool.classesAccept( 283 new ClassFinalizer(classMarkingFinalCounter)); 284 } 285 286 if (methodMarkingFinal) 287 { 288 // Make methods final, whereever possible. 289 programClassPool.classesAccept( 290 new AllMethodVisitor( 291 new MethodFinalizer(methodMarkingFinalCounter))); 292 } 293 294 if (fieldRemovalWriteonly) 295 { 296 // Mark all fields that are write-only. 297 programClassPool.classesAccept( 298 new AllMethodVisitor( 299 new AllAttributeVisitor( 300 new AllInstructionVisitor( 301 new ReadWriteFieldMarker())))); 302 303 // Count the write-only fields. 304 programClassPool.classesAccept( 305 new AllFieldVisitor( 306 new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter))); 307 } 308 else 309 { 310 // Mark all fields as read/write. 311 programClassPool.classesAccept( 312 new AllFieldVisitor( 313 new ReadWriteFieldMarker())); 314 } 315 316 // Mark all used parameters, including the 'this' parameters. 317 programClassPool.classesAccept( 318 new AllMethodVisitor( 319 new OptimizationInfoMemberFilter( 320 new ParameterUsageMarker(!methodMarkingStatic, 321 !methodRemovalParameter)))); 322 323 // Mark all methods that have side effects. 324 programClassPool.accept(new SideEffectMethodMarker()); 325 326 // System.out.println("Optimizer.execute: before evaluation simplification"); 327 // programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter())); 328 329 // Perform partial evaluation for filling out fields, method parameters, 330 // and method return values. 331 ValueFactory valueFactory = new IdentifiedValueFactory(); 332 333 if (fieldPropagationValue || 334 methodPropagationParameter || 335 methodPropagationReturnvalue) 336 { 337 // Fill out fields, method parameters, and return values, so they 338 // can be propagated. 339 InvocationUnit storingInvocationUnit = 340 new StoringInvocationUnit(valueFactory, 341 fieldPropagationValue, 342 methodPropagationParameter, 343 methodPropagationReturnvalue); 344 345 programClassPool.classesAccept( 346 new AllMethodVisitor( 347 new AllAttributeVisitor( 348 new PartialEvaluator(valueFactory, storingInvocationUnit, false)))); 349 350 // Count the constant fields and methods. 351 programClassPool.classesAccept( 352 new MultiClassVisitor( 353 new ClassVisitor[] 354 { 355 new AllFieldVisitor( 356 new ConstantMemberFilter(fieldPropagationValueCounter)), 357 new AllMethodVisitor( 358 new ConstantParameterFilter(methodPropagationParameterCounter)), 359 new AllMethodVisitor( 360 new ConstantMemberFilter(methodPropagationReturnvalueCounter)), 361 })); 362 } 363 364 InvocationUnit loadingInvocationUnit = 365 new LoadingInvocationUnit(valueFactory, 366 fieldPropagationValue, 367 methodPropagationParameter, 368 methodPropagationReturnvalue); 369 370 if (codeSimplificationAdvanced) 371 { 372 // Simplify based on partial evaluation, propagating constant 373 // field values, method parameter values, and return values. 374 programClassPool.classesAccept( 375 new AllMethodVisitor( 376 new AllAttributeVisitor( 377 new EvaluationSimplifier( 378 new PartialEvaluator(valueFactory, loadingInvocationUnit, false), 379 codeSimplificationAdvancedCounter)))); 380 } 381 382 if (codeRemovalAdvanced) 383 { 384 // Remove code based on partial evaluation, also removing unused 385 // parameters from method invocations, and making methods static 386 // if possible. 387 programClassPool.classesAccept( 388 new AllMethodVisitor( 389 new AllAttributeVisitor( 390 new EvaluationShrinker( 391 new PartialEvaluator(valueFactory, loadingInvocationUnit, !codeSimplificationAdvanced), 392 deletedCounter, addedCounter)))); 393 } 394 395 if (methodRemovalParameter) 396 { 397 // Shrink the parameters in the method descriptors. 398 programClassPool.classesAccept( 399 new AllMethodVisitor( 400 new OptimizationInfoMemberFilter( 401 new MethodDescriptorShrinker()))); 402 } 403 404 if (methodMarkingStatic) 405 { 406 // Make all non-static methods that don't require the 'this' 407 // parameter static. 408 programClassPool.classesAccept( 409 new AllMethodVisitor( 410 new OptimizationInfoMemberFilter( 411 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC, 412 new MethodStaticizer(methodMarkingStaticCounter))))); 413 } 414 415 if (methodRemovalParameter) 416 { 417 // Fix all references to class members. 418 // This operation also updates the stack sizes. 419 programClassPool.classesAccept( 420 new MemberReferenceFixer()); 421 } 422 423 if (methodRemovalParameter || 424 methodMarkingPrivate || 425 methodMarkingStatic) 426 { 427 // Remove all unused parameters from the byte code, shifting all 428 // remaining variables. 429 // This operation also updates the local variable frame sizes. 430 programClassPool.classesAccept( 431 new AllMethodVisitor( 432 new AllAttributeVisitor( 433 new ParameterShrinker(methodRemovalParameterCounter)))); 434 } 435 else if (codeRemovalAdvanced) 436 { 437 // Just update the local variable frame sizes. 438 programClassPool.classesAccept( 439 new AllMethodVisitor( 440 new AllAttributeVisitor( 441 new StackSizeUpdater()))); 442 } 443 444 // // Specializing the class member descriptors seems to increase the 445 // // class file size, on average. 446 // // Specialize all class member descriptors. 447 // programClassPool.classesAccept(new AllMemberVisitor( 448 // new OptimizationInfoMemberFilter( 449 // new MemberDescriptorSpecializer()))); 450 // 451 // // Fix all references to classes, for MemberDescriptorSpecializer. 452 // programClassPool.classesAccept(new AllMemberVisitor( 453 // new OptimizationInfoMemberFilter( 454 // new ClassReferenceFixer(true)))); 455 456 // Mark all classes with package visible members. 457 // Mark all exception catches of methods. 458 // Count all method invocations. 459 // Mark super invocations and other access of methods. 460 programClassPool.classesAccept( 461 new MultiClassVisitor( 462 new ClassVisitor[] 463 { 464 new AllConstantVisitor( 465 new PackageVisibleMemberInvokingClassMarker()), 466 new AllMethodVisitor( 467 new MultiMemberVisitor( 468 new MemberVisitor[] 469 { 470 new PackageVisibleMemberContainingClassMarker(), 471 new AllAttributeVisitor( 472 new MultiAttributeVisitor( 473 new AttributeVisitor[] 474 { 475 new CatchExceptionMarker(), 476 new AllInstructionVisitor( 477 new MultiInstructionVisitor( 478 new InstructionVisitor[] 479 { 480 new InstantiationClassMarker(), 481 new InstanceofClassMarker(), 482 new DotClassMarker(), 483 new MethodInvocationMarker(), 484 new SuperInvocationMarker(), 485 new BackwardBranchMarker(), 486 new AccessMethodMarker(), 487 })), 488 new AllExceptionInfoVisitor( 489 new ExceptionHandlerConstantVisitor( 490 new ReferencedClassVisitor( 491 new CaughtClassMarker()))), 492 })), 493 })), 494 })); 495 496 if (classMergingVertical) 497 { 498 // Merge classes into their superclasses or interfaces. 499 programClassPool.classesAccept( 500 new VerticalClassMerger(configuration.allowAccessModification, 501 configuration.mergeInterfacesAggressively, 502 classMergingVerticalCounter)); 503 } 504 505 if (classMergingHorizontal) 506 { 507 // Merge classes into their sibling classes. 508 programClassPool.classesAccept( 509 new HorizontalClassMerger(configuration.allowAccessModification, 510 configuration.mergeInterfacesAggressively, 511 classMergingHorizontalCounter)); 512 } 513 514 if (classMergingVertical || 515 classMergingHorizontal) 516 { 517 // Clean up inner class attributes to avoid loops. 518 programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover()); 519 520 // Update references to merged classes. 521 programClassPool.classesAccept(new TargetClassChanger()); 522 programClassPool.classesAccept(new ClassReferenceFixer(true)); 523 programClassPool.classesAccept(new MemberReferenceFixer()); 524 525 if (configuration.allowAccessModification) 526 { 527 // Fix the access flags of referenced merged classes and their 528 // class members. 529 programClassPool.classesAccept( 530 new AllConstantVisitor( 531 new AccessFixer())); 532 } 533 } 534 535 if (methodRemovalParameter || 536 classMergingVertical || 537 classMergingHorizontal) 538 { 539 // Tweak the descriptors of duplicate initializers. 540 programClassPool.classesAccept( 541 new AllMethodVisitor( 542 new DuplicateInitializerFixer(initializerFixCounter))); 543 544 if (initializerFixCounter.getCount() > 0) 545 { 546 // Fix all invocations of tweaked initializers. 547 programClassPool.classesAccept( 548 new AllMethodVisitor( 549 new AllAttributeVisitor( 550 new DuplicateInitializerInvocationFixer(addedCounter)))); 551 552 // Fix all references to tweaked initializers. 553 programClassPool.classesAccept(new MemberReferenceFixer()); 554 } 555 } 556 557 if (methodInliningUnique) 558 { 559 // Inline methods that are only invoked once. 560 programClassPool.classesAccept( 561 new AllMethodVisitor( 562 new AllAttributeVisitor( 563 new MethodInliner(configuration.microEdition, 564 configuration.allowAccessModification, 565 true, 566 methodInliningUniqueCounter)))); 567 } 568 569 if (methodInliningShort) 570 { 571 // Inline short methods. 572 programClassPool.classesAccept( 573 new AllMethodVisitor( 574 new AllAttributeVisitor( 575 new MethodInliner(configuration.microEdition, 576 configuration.allowAccessModification, 577 false, 578 methodInliningShortCounter)))); 579 } 580 581 if (methodInliningTailrecursion) 582 { 583 // Simplify tail recursion calls. 584 programClassPool.classesAccept( 585 new AllMethodVisitor( 586 new AllAttributeVisitor( 587 new TailRecursionSimplifier(methodInliningTailrecursionCounter)))); 588 } 589 590 if (fieldMarkingPrivate || 591 methodMarkingPrivate) 592 { 593 // Mark all class members that can not be made private. 594 programClassPool.classesAccept( 595 new NonPrivateMemberMarker()); 596 } 597 598 if (fieldMarkingPrivate || 599 methodMarkingPrivate) 600 { 601 // Make all non-private fields private, whereever possible. 602 programClassPool.classesAccept( 603 new AllFieldVisitor( 604 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 605 new MemberPrivatizer(fieldMarkingPrivateCounter)))); 606 } 607 608 if (methodMarkingPrivate) 609 { 610 // Make all non-private methods private, whereever possible. 611 programClassPool.classesAccept( 612 new ClassAccessFilter(0, ClassConstants.INTERNAL_ACC_INTERFACE, 613 new AllMethodVisitor( 614 new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, 615 new MemberPrivatizer(methodMarkingPrivateCounter))))); 616 } 617 618 if ((methodInliningUnique || 619 methodInliningShort || 620 methodInliningTailrecursion) && 621 configuration.allowAccessModification) 622 { 623 // Fix the access flags of referenced classes and class members, 624 // for MethodInliner. 625 programClassPool.classesAccept( 626 new AllConstantVisitor( 627 new AccessFixer())); 628 } 629 630 if (methodRemovalParameter || 631 classMergingVertical || 632 classMergingHorizontal || 633 methodMarkingPrivate) 634 { 635 // Fix invocations of interface methods, of methods that have become 636 // non-abstract or private, and of methods that have moved to a 637 // different package. 638 programClassPool.classesAccept( 639 new AllMemberVisitor( 640 new AllAttributeVisitor( 641 new MethodInvocationFixer()))); 642 } 643 644 if (codeMerging) 645 { 646 // Share common blocks of code at branches. 647 programClassPool.classesAccept( 648 new AllMethodVisitor( 649 new AllAttributeVisitor( 650 new GotoCommonCodeReplacer(codeMergingCounter)))); 651 } 652 653 // Create a branch target marker and a code attribute editor that can 654 // be reused for all code attributes. 655 BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); 656 CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 657 658 List peepholeOptimizations = new ArrayList(); 659 if (codeSimplificationVariable) 660 { 661 // Peephole optimizations involving local variables. 662 peepholeOptimizations.add( 663 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 664 InstructionSequenceConstants.VARIABLE, 665 branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter)); 666 } 667 668 if (codeSimplificationArithmetic) 669 { 670 // Peephole optimizations involving arithmetic operations. 671 peepholeOptimizations.add( 672 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 673 InstructionSequenceConstants.ARITHMETIC, 674 branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter)); 675 } 676 677 if (codeSimplificationCast) 678 { 679 // Peephole optimizations involving cast operations. 680 peepholeOptimizations.add( 681 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 682 InstructionSequenceConstants.CAST, 683 branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter)); 684 } 685 686 if (codeSimplificationField) 687 { 688 // Peephole optimizations involving fields. 689 peepholeOptimizations.add( 690 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 691 InstructionSequenceConstants.FIELD, 692 branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter)); 693 } 694 695 if (codeSimplificationBranch) 696 { 697 // Peephole optimizations involving branches. 698 peepholeOptimizations.add( 699 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 700 InstructionSequenceConstants.BRANCH, 701 branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter)); 702 703 // Include optimization of branches to branches and returns. 704 peepholeOptimizations.add( 705 new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); 706 peepholeOptimizations.add( 707 new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); 708 } 709 710 if (!peepholeOptimizations.isEmpty()) 711 { 712 // Convert the list into an array. 713 InstructionVisitor[] peepholeOptimizationsArray = 714 new InstructionVisitor[peepholeOptimizations.size()]; 715 peepholeOptimizations.toArray(peepholeOptimizationsArray); 716 717 // Perform the peephole optimisations. 718 programClassPool.classesAccept( 719 new AllMethodVisitor( 720 new AllAttributeVisitor( 721 new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor, 722 new MultiInstructionVisitor( 723 peepholeOptimizationsArray))))); 724 } 725 726 if (codeRemovalException) 727 { 728 // Remove unnecessary exception handlers. 729 programClassPool.classesAccept( 730 new AllMethodVisitor( 731 new AllAttributeVisitor( 732 new UnreachableExceptionRemover(codeRemovalExceptionCounter)))); 733 } 734 735 if (codeRemovalSimple) 736 { 737 // Remove unreachable code. 738 programClassPool.classesAccept( 739 new AllMethodVisitor( 740 new AllAttributeVisitor( 741 new UnreachableCodeRemover(deletedCounter)))); 742 } 743 744 if (codeRemovalVariable) 745 { 746 // Remove all unused local variables. 747 programClassPool.classesAccept( 748 new AllMethodVisitor( 749 new AllAttributeVisitor( 750 new VariableShrinker(codeRemovalVariableCounter)))); 751 } 752 else 753 { 754 // Clean up all unused local variables. 755 programClassPool.classesAccept( 756 new AllMethodVisitor( 757 new AllAttributeVisitor( 758 new VariableCleaner()))); 759 } 760 761 if (codeAllocationVariable) 762 { 763 // Optimize the variables. 764 programClassPool.classesAccept( 765 new AllMethodVisitor( 766 new AllAttributeVisitor( 767 new VariableOptimizer(false, codeAllocationVariableCounter)))); 768 } 769 770 int classMarkingFinalCount = classMarkingFinalCounter .getCount(); 771 int classMergingVerticalCount = classMergingVerticalCounter .getCount(); 772 int classMergingHorizontalCount = classMergingHorizontalCounter .getCount(); 773 int fieldRemovalWriteonlyCount = fieldRemovalWriteonlyCounter .getCount(); 774 int fieldMarkingPrivateCount = fieldMarkingPrivateCounter .getCount(); 775 int fieldPropagationValueCount = fieldPropagationValueCounter .getCount(); 776 int methodMarkingPrivateCount = methodMarkingPrivateCounter .getCount(); 777 int methodMarkingStaticCount = methodMarkingStaticCounter .getCount(); 778 int methodMarkingFinalCount = methodMarkingFinalCounter .getCount(); 779 int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter.getCount(); 780 int methodPropagationParameterCount = methodPropagationParameterCounter .getCount(); 781 int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount(); 782 int methodInliningShortCount = methodInliningShortCounter .getCount(); 783 int methodInliningUniqueCount = methodInliningUniqueCounter .getCount(); 784 int methodInliningTailrecursionCount = methodInliningTailrecursionCounter .getCount(); 785 int codeMergingCount = codeMergingCounter .getCount(); 786 int codeSimplificationVariableCount = codeSimplificationVariableCounter .getCount(); 787 int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter.getCount(); 788 int codeSimplificationCastCount = codeSimplificationCastCounter .getCount(); 789 int codeSimplificationFieldCount = codeSimplificationFieldCounter .getCount(); 790 int codeSimplificationBranchCount = codeSimplificationBranchCounter .getCount(); 791 int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter .getCount(); 792 int codeRemovalCount = deletedCounter .getCount() - addedCounter.getCount(); 793 int codeRemovalVariableCount = codeRemovalVariableCounter .getCount(); 794 int codeRemovalExceptionCount = codeRemovalExceptionCounter .getCount(); 795 int codeAllocationVariableCount = codeAllocationVariableCounter .getCount(); 796 797 if (configuration.verbose) 798 { 799 System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal)); 800 System.out.println(" Number of vertically merged classes: " + classMergingVerticalCount + disabled(classMergingVertical)); 801 System.out.println(" Number of horizontally merged classes: " + classMergingHorizontalCount + disabled(classMergingHorizontal)); 802 System.out.println(" Number of removed write-only fields: " + fieldRemovalWriteonlyCount + disabled(fieldRemovalWriteonly)); 803 System.out.println(" Number of privatized fields: " + fieldMarkingPrivateCount + disabled(fieldMarkingPrivate)); 804 System.out.println(" Number of inlined constant fields: " + fieldPropagationValueCount + disabled(fieldPropagationValue)); 805 System.out.println(" Number of privatized methods: " + methodMarkingPrivateCount + disabled(methodMarkingPrivate)); 806 System.out.println(" Number of staticized methods: " + methodMarkingStaticCount + disabled(methodMarkingStatic)); 807 System.out.println(" Number of finalized methods: " + methodMarkingFinalCount + disabled(methodMarkingFinal)); 808 System.out.println(" Number of removed method parameters: " + methodRemovalParameterCount + disabled(methodRemovalParameter)); 809 System.out.println(" Number of inlined constant parameters: " + methodPropagationParameterCount + disabled(methodPropagationParameter)); 810 System.out.println(" Number of inlined constant return values: " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue)); 811 System.out.println(" Number of inlined short method calls: " + methodInliningShortCount + disabled(methodInliningShort)); 812 System.out.println(" Number of inlined unique method calls: " + methodInliningUniqueCount + disabled(methodInliningUnique)); 813 System.out.println(" Number of inlined tail recursion calls: " + methodInliningTailrecursionCount + disabled(methodInliningTailrecursion)); 814 System.out.println(" Number of merged code blocks: " + codeMergingCount + disabled(codeMerging)); 815 System.out.println(" Number of variable peephole optimizations: " + codeSimplificationVariableCount + disabled(codeSimplificationVariable)); 816 System.out.println(" Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic)); 817 System.out.println(" Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast)); 818 System.out.println(" Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField)); 819 System.out.println(" Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch)); 820 System.out.println(" Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced)); 821 System.out.println(" Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced)); 822 System.out.println(" Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable)); 823 System.out.println(" Number of removed exception blocks: " + codeRemovalExceptionCount + disabled(codeRemovalException)); 824 System.out.println(" Number of optimized local variable frames: " + codeAllocationVariableCount + disabled(codeAllocationVariable)); 825 } 826 827 return classMarkingFinalCount > 0 || 828 classMergingVerticalCount > 0 || 829 classMergingHorizontalCount > 0 || 830 fieldRemovalWriteonlyCount > 0 || 831 fieldMarkingPrivateCount > 0 || 832 methodMarkingPrivateCount > 0 || 833 methodMarkingStaticCount > 0 || 834 methodMarkingFinalCount > 0 || 835 fieldPropagationValueCount > 0 || 836 methodRemovalParameterCount > 0 || 837 methodPropagationParameterCount > 0 || 838 methodPropagationReturnvalueCount > 0 || 839 methodInliningShortCount > 0 || 840 methodInliningUniqueCount > 0 || 841 methodInliningTailrecursionCount > 0 || 842 codeMergingCount > 0 || 843 codeSimplificationVariableCount > 0 || 844 codeSimplificationArithmeticCount > 0 || 845 codeSimplificationCastCount > 0 || 846 codeSimplificationFieldCount > 0 || 847 codeSimplificationBranchCount > 0 || 848 codeSimplificationAdvancedCount > 0 || 849 codeRemovalCount > 0 || 850 codeRemovalVariableCount > 0 || 851 codeRemovalExceptionCount > 0 || 852 codeAllocationVariableCount > 0; 853 } 854 855 856 /** 857 * Returns a String indicating whether the given flag is enabled or 858 * disabled. 859 */ 860 private String disabled(boolean flag) 861 { 862 return flag ? "" : " (disabled)"; 863 } 864 865 866 /** 867 * Returns a String indicating whether the given flags are enabled or 868 * disabled. 869 */ 870 private String disabled(boolean flag1, boolean flag2) 871 { 872 return flag1 && flag2 ? "" : 873 flag1 || flag2 ? " (partially disabled)" : 874 " (disabled)"; 875 } 876 } 877