1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 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 * 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 */ 21package proguard.optimize; 22 23import proguard.*; 24import proguard.classfile.*; 25import proguard.classfile.attribute.visitor.*; 26import proguard.classfile.constant.visitor.*; 27import proguard.classfile.editor.*; 28import proguard.classfile.instruction.visitor.*; 29import proguard.classfile.util.MethodLinker; 30import proguard.classfile.visitor.*; 31import proguard.evaluation.InvocationUnit; 32import proguard.evaluation.value.*; 33import proguard.optimize.evaluation.*; 34import proguard.optimize.info.*; 35import proguard.optimize.peephole.*; 36import proguard.util.*; 37 38import java.io.IOException; 39import java.util.*; 40 41/** 42 * This class optimizes class pools according to a given configuration. 43 * 44 * @author Eric Lafortune 45 */ 46public class Optimizer 47{ 48 private static final String CLASS_MARKING_FINAL = "class/marking/final"; 49 private static final String CLASS_UNBOXING_ENUM = "class/unboxing/enum"; 50 private static final String CLASS_MERGING_VERTICAL = "class/merging/vertical"; 51 private static final String CLASS_MERGING_HORIZONTAL = "class/merging/horizontal"; 52 private static final String FIELD_REMOVAL_WRITEONLY = "field/removal/writeonly"; 53 private static final String FIELD_MARKING_PRIVATE = "field/marking/private"; 54 private static final String FIELD_PROPAGATION_VALUE = "field/propagation/value"; 55 private static final String METHOD_MARKING_PRIVATE = "method/marking/private"; 56 private static final String METHOD_MARKING_STATIC = "method/marking/static"; 57 private static final String METHOD_MARKING_FINAL = "method/marking/final"; 58 private static final String METHOD_REMOVAL_PARAMETER = "method/removal/parameter"; 59 private static final String METHOD_PROPAGATION_PARAMETER = "method/propagation/parameter"; 60 private static final String METHOD_PROPAGATION_RETURNVALUE = "method/propagation/returnvalue"; 61 private static final String METHOD_INLINING_SHORT = "method/inlining/short"; 62 private static final String METHOD_INLINING_UNIQUE = "method/inlining/unique"; 63 private static final String METHOD_INLINING_TAILRECURSION = "method/inlining/tailrecursion"; 64 private static final String CODE_MERGING = "code/merging"; 65 private static final String CODE_SIMPLIFICATION_VARIABLE = "code/simplification/variable"; 66 private static final String CODE_SIMPLIFICATION_ARITHMETIC = "code/simplification/arithmetic"; 67 private static final String CODE_SIMPLIFICATION_CAST = "code/simplification/cast"; 68 private static final String CODE_SIMPLIFICATION_FIELD = "code/simplification/field"; 69 private static final String CODE_SIMPLIFICATION_BRANCH = "code/simplification/branch"; 70 private static final String CODE_SIMPLIFICATION_STRING = "code/simplification/string"; 71 private static final String CODE_SIMPLIFICATION_ADVANCED = "code/simplification/advanced"; 72 private static final String CODE_REMOVAL_ADVANCED = "code/removal/advanced"; 73 private static final String CODE_REMOVAL_SIMPLE = "code/removal/simple"; 74 private static final String CODE_REMOVAL_VARIABLE = "code/removal/variable"; 75 private static final String CODE_REMOVAL_EXCEPTION = "code/removal/exception"; 76 private static final String CODE_ALLOCATION_VARIABLE = "code/allocation/variable"; 77 78 79 public static final String[] OPTIMIZATION_NAMES = new String[] 80 { 81 CLASS_MARKING_FINAL, 82 CLASS_MERGING_VERTICAL, 83 CLASS_MERGING_HORIZONTAL, 84 FIELD_REMOVAL_WRITEONLY, 85 FIELD_MARKING_PRIVATE, 86 FIELD_PROPAGATION_VALUE, 87 METHOD_MARKING_PRIVATE, 88 METHOD_MARKING_STATIC, 89 METHOD_MARKING_FINAL, 90 METHOD_REMOVAL_PARAMETER, 91 METHOD_PROPAGATION_PARAMETER, 92 METHOD_PROPAGATION_RETURNVALUE, 93 METHOD_INLINING_SHORT, 94 METHOD_INLINING_UNIQUE, 95 METHOD_INLINING_TAILRECURSION, 96 CODE_MERGING, 97 CODE_SIMPLIFICATION_VARIABLE, 98 CODE_SIMPLIFICATION_ARITHMETIC, 99 CODE_SIMPLIFICATION_CAST, 100 CODE_SIMPLIFICATION_FIELD, 101 CODE_SIMPLIFICATION_BRANCH, 102 CODE_SIMPLIFICATION_STRING, 103 CODE_SIMPLIFICATION_ADVANCED, 104 CODE_REMOVAL_ADVANCED, 105 CODE_REMOVAL_SIMPLE, 106 CODE_REMOVAL_VARIABLE, 107 CODE_REMOVAL_EXCEPTION, 108 CODE_ALLOCATION_VARIABLE, 109 }; 110 111 112 private final Configuration configuration; 113 114 115 /** 116 * Creates a new Optimizer. 117 */ 118 public Optimizer(Configuration configuration) 119 { 120 this.configuration = configuration; 121 } 122 123 124 /** 125 * Performs optimization of the given program class pool. 126 */ 127 public boolean execute(ClassPool programClassPool, 128 ClassPool libraryClassPool) throws IOException 129 { 130 // Check if we have at least some keep commands. 131 if (configuration.keep == null && 132 configuration.applyMapping == null && 133 configuration.printMapping == null) 134 { 135 throw new IOException("You have to specify '-keep' options for the optimization step."); 136 } 137 138 // Create a matcher for filtering optimizations. 139 StringMatcher filter = configuration.optimizations != null ? 140 new ListParser(new NameParser()).parse(configuration.optimizations) : 141 new ConstantMatcher(true); 142 143 boolean classMarkingFinal = filter.matches(CLASS_MARKING_FINAL); 144 boolean classUnboxingEnum = filter.matches(CLASS_UNBOXING_ENUM); 145 boolean classMergingVertical = filter.matches(CLASS_MERGING_VERTICAL); 146 boolean classMergingHorizontal = filter.matches(CLASS_MERGING_HORIZONTAL); 147 boolean fieldRemovalWriteonly = filter.matches(FIELD_REMOVAL_WRITEONLY); 148 boolean fieldMarkingPrivate = filter.matches(FIELD_MARKING_PRIVATE); 149 boolean fieldPropagationValue = filter.matches(FIELD_PROPAGATION_VALUE); 150 boolean methodMarkingPrivate = filter.matches(METHOD_MARKING_PRIVATE); 151 boolean methodMarkingStatic = filter.matches(METHOD_MARKING_STATIC); 152 boolean methodMarkingFinal = filter.matches(METHOD_MARKING_FINAL); 153 boolean methodRemovalParameter = filter.matches(METHOD_REMOVAL_PARAMETER); 154 boolean methodPropagationParameter = filter.matches(METHOD_PROPAGATION_PARAMETER); 155 boolean methodPropagationReturnvalue = filter.matches(METHOD_PROPAGATION_RETURNVALUE); 156 boolean methodInliningShort = filter.matches(METHOD_INLINING_SHORT); 157 boolean methodInliningUnique = filter.matches(METHOD_INLINING_UNIQUE); 158 boolean methodInliningTailrecursion = filter.matches(METHOD_INLINING_TAILRECURSION); 159 boolean codeMerging = filter.matches(CODE_MERGING); 160 boolean codeSimplificationVariable = filter.matches(CODE_SIMPLIFICATION_VARIABLE); 161 boolean codeSimplificationArithmetic = filter.matches(CODE_SIMPLIFICATION_ARITHMETIC); 162 boolean codeSimplificationCast = filter.matches(CODE_SIMPLIFICATION_CAST); 163 boolean codeSimplificationField = filter.matches(CODE_SIMPLIFICATION_FIELD); 164 boolean codeSimplificationBranch = filter.matches(CODE_SIMPLIFICATION_BRANCH); 165 boolean codeSimplificationString = filter.matches(CODE_SIMPLIFICATION_STRING); 166 boolean codeSimplificationAdvanced = filter.matches(CODE_SIMPLIFICATION_ADVANCED); 167 boolean codeRemovalAdvanced = filter.matches(CODE_REMOVAL_ADVANCED); 168 boolean codeRemovalSimple = filter.matches(CODE_REMOVAL_SIMPLE); 169 boolean codeRemovalVariable = filter.matches(CODE_REMOVAL_VARIABLE); 170 boolean codeRemovalException = filter.matches(CODE_REMOVAL_EXCEPTION); 171 boolean codeAllocationVariable = filter.matches(CODE_ALLOCATION_VARIABLE); 172 173 // Create counters to count the numbers of optimizations. 174 ClassCounter classMarkingFinalCounter = new ClassCounter(); 175 ClassCounter classUnboxingEnumCounter = new ClassCounter(); 176 ClassCounter classMergingVerticalCounter = new ClassCounter(); 177 ClassCounter classMergingHorizontalCounter = new ClassCounter(); 178 MemberCounter fieldRemovalWriteonlyCounter = new MemberCounter(); 179 MemberCounter fieldMarkingPrivateCounter = new MemberCounter(); 180 MemberCounter fieldPropagationValueCounter = new MemberCounter(); 181 MemberCounter methodMarkingPrivateCounter = new MemberCounter(); 182 MemberCounter methodMarkingStaticCounter = new MemberCounter(); 183 MemberCounter methodMarkingFinalCounter = new MemberCounter(); 184 MemberCounter methodRemovalParameterCounter = new MemberCounter(); 185 MemberCounter methodPropagationParameterCounter = new MemberCounter(); 186 MemberCounter methodPropagationReturnvalueCounter = new MemberCounter(); 187 InstructionCounter methodInliningShortCounter = new InstructionCounter(); 188 InstructionCounter methodInliningUniqueCounter = new InstructionCounter(); 189 InstructionCounter methodInliningTailrecursionCounter = new InstructionCounter(); 190 InstructionCounter codeMergingCounter = new InstructionCounter(); 191 InstructionCounter codeSimplificationVariableCounter = new InstructionCounter(); 192 InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter(); 193 InstructionCounter codeSimplificationCastCounter = new InstructionCounter(); 194 InstructionCounter codeSimplificationFieldCounter = new InstructionCounter(); 195 InstructionCounter codeSimplificationBranchCounter = new InstructionCounter(); 196 InstructionCounter codeSimplificationStringCounter = new InstructionCounter(); 197 InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter(); 198 InstructionCounter deletedCounter = new InstructionCounter(); 199 InstructionCounter addedCounter = new InstructionCounter(); 200 MemberCounter codeRemovalVariableCounter = new MemberCounter(); 201 ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter(); 202 MemberCounter codeAllocationVariableCounter = new MemberCounter(); 203 MemberCounter initializerFixCounter1 = new MemberCounter(); 204 MemberCounter initializerFixCounter2 = new MemberCounter(); 205 206 // Some optimizations are required by other optimizations. 207 codeSimplificationAdvanced = 208 codeSimplificationAdvanced || 209 fieldPropagationValue || 210 methodPropagationParameter || 211 methodPropagationReturnvalue; 212 213 codeRemovalAdvanced = 214 codeRemovalAdvanced || 215 fieldRemovalWriteonly || 216 methodMarkingStatic || 217 methodRemovalParameter; 218 219 codeRemovalSimple = 220 codeRemovalSimple || 221 codeSimplificationBranch; 222 223 codeRemovalException = 224 codeRemovalException || 225 codeRemovalAdvanced || 226 codeRemovalSimple; 227 228 // Clean up any old visitor info. 229 programClassPool.classesAccept(new ClassCleaner()); 230 libraryClassPool.classesAccept(new ClassCleaner()); 231 232 // Link all methods that should get the same optimization info. 233 programClassPool.classesAccept(new BottomClassFilter( 234 new MethodLinker())); 235 libraryClassPool.classesAccept(new BottomClassFilter( 236 new MethodLinker())); 237 238 // Create a visitor for marking the seeds. 239 KeepMarker keepMarker = new KeepMarker(); 240 ClassPoolVisitor classPoolvisitor = 241 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, 242 keepMarker, 243 keepMarker, 244 false, 245 true, 246 false); 247 // Mark the seeds. 248 programClassPool.accept(classPoolvisitor); 249 libraryClassPool.accept(classPoolvisitor); 250 251 // All library classes and library class members remain unchanged. 252 libraryClassPool.classesAccept(keepMarker); 253 libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker)); 254 255 // We also keep all classes that are involved in .class constructs. 256 // We're not looking at enum classes though, so they can be simplified. 257 programClassPool.classesAccept( 258 new ClassAccessFilter(0, ClassConstants.ACC_ENUM, 259 new AllMethodVisitor( 260 new AllAttributeVisitor( 261 new AllInstructionVisitor( 262 new DotClassClassVisitor(keepMarker)))))); 263 264 // We also keep all classes that are accessed dynamically. 265 programClassPool.classesAccept( 266 new AllConstantVisitor( 267 new ConstantTagFilter(ClassConstants.CONSTANT_String, 268 new ReferencedClassVisitor(keepMarker)))); 269 270 // We also keep all class members that are accessed dynamically. 271 programClassPool.classesAccept( 272 new AllConstantVisitor( 273 new ConstantTagFilter(ClassConstants.CONSTANT_String, 274 new ReferencedMemberVisitor(keepMarker)))); 275 276 // We also keep all bootstrap method signatures. 277 programClassPool.classesAccept( 278 new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7, 279 new AllAttributeVisitor( 280 new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods, 281 new AllBootstrapMethodInfoVisitor( 282 new BootstrapMethodHandleTraveler( 283 new MethodrefTraveler( 284 new ReferencedMemberVisitor(keepMarker)))))))); 285 286 // We also keep all bootstrap method arguments that point to methods. 287 // These arguments are typically the method handles for 288 // java.lang.invoke.LambdaMetafactory#metafactory, which provides the 289 // implementations for closures. 290 programClassPool.classesAccept( 291 new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7, 292 new AllAttributeVisitor( 293 new AttributeNameFilter(ClassConstants.ATTR_BootstrapMethods, 294 new AllBootstrapMethodInfoVisitor( 295 new BootstrapMethodArgumentVisitor( 296 new MethodrefTraveler( 297 new ReferencedMemberVisitor(keepMarker)))))))); 298 299 // We also keep all classes (and their methods) returned by dynamic 300 // method invocations. They may return dynamic implementations of 301 // interfaces that otherwise appear unused. 302 programClassPool.classesAccept( 303 new ClassVersionFilter(ClassConstants.CLASS_VERSION_1_7, 304 new AllConstantVisitor( 305 new DynamicReturnedClassVisitor( 306 new MultiClassVisitor(new ClassVisitor[] 307 { 308 keepMarker, 309 new AllMemberVisitor(keepMarker) 310 }))))); 311 312 // Attach some optimization info to all classes and class members, so 313 // it can be filled out later. 314 programClassPool.classesAccept(new ClassOptimizationInfoSetter()); 315 316 programClassPool.classesAccept(new AllMemberVisitor( 317 new MemberOptimizationInfoSetter())); 318 319 if (configuration.assumeNoSideEffects != null) 320 { 321 // Create a visitor for marking methods that don't have any side effects. 322 NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker(); 323 ClassPoolVisitor noClassPoolvisitor = 324 ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.assumeNoSideEffects, 325 null, 326 noSideEffectMethodMarker); 327 328 // Mark the seeds. 329 programClassPool.accept(noClassPoolvisitor); 330 libraryClassPool.accept(noClassPoolvisitor); 331 } 332 333 if (classMarkingFinal) 334 { 335 // Make classes final, whereever possible. 336 programClassPool.classesAccept( 337 new ClassFinalizer(classMarkingFinalCounter)); 338 } 339 340 if (methodMarkingFinal) 341 { 342 // Make methods final, whereever possible. 343 programClassPool.classesAccept( 344 new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE, 345 new AllMethodVisitor( 346 new MethodFinalizer(methodMarkingFinalCounter)))); 347 } 348 349 if (fieldRemovalWriteonly) 350 { 351 // Mark all fields that are write-only. 352 programClassPool.classesAccept( 353 new AllMethodVisitor( 354 new AllAttributeVisitor( 355 new AllInstructionVisitor( 356 new ReadWriteFieldMarker())))); 357 358 // Count the write-only fields. 359 programClassPool.classesAccept( 360 new AllFieldVisitor( 361 new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter))); 362 } 363 else 364 { 365 // Mark all fields as read/write. 366 programClassPool.classesAccept( 367 new AllFieldVisitor( 368 new ReadWriteFieldMarker())); 369 } 370 371 if (classUnboxingEnum) 372 { 373 ClassCounter counter = new ClassCounter(); 374 375 // Mark all final enums that qualify as simple enums. 376 programClassPool.classesAccept( 377 new ClassAccessFilter(ClassConstants.ACC_FINAL | 378 ClassConstants.ACC_ENUM, 0, 379 new SimpleEnumClassChecker())); 380 381 // Count the preliminary number of simple enums. 382 programClassPool.classesAccept( 383 new SimpleEnumFilter(counter)); 384 385 // Only continue checking simple enums if there are any candidates. 386 if (counter.getCount() > 0) 387 { 388 // Unmark all simple enums that are explicitly used as objects. 389 programClassPool.classesAccept( 390 new SimpleEnumUseChecker()); 391 392 // Count the definitive number of simple enums. 393 programClassPool.classesAccept( 394 new SimpleEnumFilter(classUnboxingEnumCounter)); 395 396 // Only start handling simple enums if there are any. 397 if (classUnboxingEnumCounter.getCount() > 0) 398 { 399 // Simplify the use of the enum classes in code. 400 programClassPool.classesAccept( 401 new AllMethodVisitor( 402 new AllAttributeVisitor( 403 new SimpleEnumUseSimplifier()))); 404 405 // Simplify the static initializers of simple enum classes. 406 programClassPool.classesAccept( 407 new SimpleEnumFilter( 408 new SimpleEnumClassSimplifier())); 409 410 // Simplify the use of the enum classes in descriptors. 411 programClassPool.classesAccept( 412 new SimpleEnumDescriptorSimplifier()); 413 414 // Update references to class members with simple enum classes. 415 programClassPool.classesAccept(new MemberReferenceFixer()); 416 } 417 } 418 } 419 420 // Mark all used parameters, including the 'this' parameters. 421 programClassPool.classesAccept( 422 new AllMethodVisitor( 423 new OptimizationInfoMemberFilter( 424 new ParameterUsageMarker(!methodMarkingStatic, 425 !methodRemovalParameter)))); 426 427 // Mark all classes that have static initializers. 428 programClassPool.classesAccept(new StaticInitializerContainingClassMarker()); 429 430 // Mark all methods that have side effects. 431 programClassPool.accept(new SideEffectMethodMarker()); 432 433// System.out.println("Optimizer.execute: before evaluation simplification"); 434// programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new ClassPrinter())); 435 436 // Perform partial evaluation for filling out fields, method parameters, 437 // and method return values, so they can be propagated. 438 if (fieldPropagationValue || 439 methodPropagationParameter || 440 methodPropagationReturnvalue) 441 { 442 // We'll create values to be stored with fields, method parameters, 443 // and return values. 444 ValueFactory valueFactory = new ParticularValueFactory(); 445 ValueFactory detailedValueFactory = new DetailedValueFactory(); 446 447 InvocationUnit storingInvocationUnit = 448 new StoringInvocationUnit(valueFactory, 449 fieldPropagationValue, 450 methodPropagationParameter, 451 methodPropagationReturnvalue); 452 453 // Evaluate synthetic classes in more detail, notably to propagate 454 // the arrays of the classes generated for enum switch statements. 455 programClassPool.classesAccept( 456 new ClassAccessFilter(ClassConstants.ACC_SYNTHETIC, 0, 457 new AllMethodVisitor( 458 new AllAttributeVisitor( 459 new PartialEvaluator(detailedValueFactory, storingInvocationUnit, false))))); 460 461 // Evaluate non-synthetic classes. 462 programClassPool.classesAccept( 463 new ClassAccessFilter(0, ClassConstants.ACC_SYNTHETIC, 464 new AllMethodVisitor( 465 new AllAttributeVisitor( 466 new PartialEvaluator(valueFactory, storingInvocationUnit, false))))); 467 468 if (fieldPropagationValue) 469 { 470 // Count the constant fields. 471 programClassPool.classesAccept( 472 new AllFieldVisitor( 473 new ConstantMemberFilter(fieldPropagationValueCounter))); 474 } 475 476 if (methodPropagationParameter) 477 { 478 // Count the constant method parameters. 479 programClassPool.classesAccept( 480 new AllMethodVisitor( 481 new ConstantParameterFilter(methodPropagationParameterCounter))); 482 } 483 484 if (methodPropagationReturnvalue) 485 { 486 // Count the constant method return values. 487 programClassPool.classesAccept( 488 new AllMethodVisitor( 489 new ConstantMemberFilter(methodPropagationReturnvalueCounter))); 490 } 491 492 if (classUnboxingEnumCounter.getCount() > 0) 493 { 494 // Propagate the simple enum constant counts. 495 programClassPool.classesAccept( 496 new SimpleEnumFilter( 497 new SimpleEnumArrayPropagator())); 498 } 499 500 if (codeSimplificationAdvanced) 501 { 502 // Fill out constants into the arrays of synthetic classes, 503 // notably the arrays of the classes generated for enum switch 504 // statements. 505 InvocationUnit loadingInvocationUnit = 506 new LoadingInvocationUnit(valueFactory, 507 fieldPropagationValue, 508 methodPropagationParameter, 509 methodPropagationReturnvalue); 510 511 programClassPool.classesAccept( 512 new ClassAccessFilter(ClassConstants.ACC_SYNTHETIC, 0, 513 new AllMethodVisitor( 514 new AllAttributeVisitor( 515 new PartialEvaluator(valueFactory, loadingInvocationUnit, false))))); 516 } 517 } 518 519 // Perform partial evaluation again, now loading any previously stored 520 // values for fields, method parameters, and method return values. 521 ValueFactory valueFactory = new IdentifiedValueFactory(); 522 523 InvocationUnit loadingInvocationUnit = 524 new LoadingInvocationUnit(valueFactory, 525 fieldPropagationValue, 526 methodPropagationParameter, 527 methodPropagationReturnvalue); 528 529 if (codeSimplificationAdvanced) 530 { 531 // Simplify based on partial evaluation, propagating constant 532 // field values, method parameter values, and return values. 533 programClassPool.classesAccept( 534 new AllMethodVisitor( 535 new AllAttributeVisitor( 536 new EvaluationSimplifier( 537 new PartialEvaluator(valueFactory, loadingInvocationUnit, false), 538 codeSimplificationAdvancedCounter)))); 539 } 540 541 if (codeRemovalAdvanced) 542 { 543 // Remove code based on partial evaluation, also removing unused 544 // parameters from method invocations, and making methods static 545 // if possible. 546 programClassPool.classesAccept( 547 new AllMethodVisitor( 548 new AllAttributeVisitor( 549 new EvaluationShrinker( 550 new PartialEvaluator(valueFactory, loadingInvocationUnit, !codeSimplificationAdvanced), 551 deletedCounter, addedCounter)))); 552 } 553 554 if (methodRemovalParameter) 555 { 556 // Shrink the parameters in the method descriptors. 557 programClassPool.classesAccept( 558 new AllMethodVisitor( 559 new OptimizationInfoMemberFilter( 560 new MethodDescriptorShrinker()))); 561 } 562 563 if (methodMarkingStatic) 564 { 565 // Make all non-static methods that don't require the 'this' 566 // parameter static. 567 programClassPool.classesAccept( 568 new AllMethodVisitor( 569 new OptimizationInfoMemberFilter( 570 new MemberAccessFilter(0, ClassConstants.ACC_STATIC, 571 new MethodStaticizer(methodMarkingStaticCounter))))); 572 } 573 574 if (methodRemovalParameter) 575 { 576 // Fix all references to class members. 577 // This operation also updates the stack sizes. 578 programClassPool.classesAccept( 579 new MemberReferenceFixer()); 580 581 // Remove unused bootstrap method arguments. 582 programClassPool.classesAccept( 583 new AllAttributeVisitor( 584 new AllBootstrapMethodInfoVisitor( 585 new BootstrapMethodArgumentShrinker()))); 586 } 587 588 if (methodRemovalParameter || 589 methodMarkingPrivate || 590 methodMarkingStatic) 591 { 592 // Remove all unused parameters from the byte code, shifting all 593 // remaining variables. 594 // This operation also updates the local variable frame sizes. 595 programClassPool.classesAccept( 596 new AllMethodVisitor( 597 new AllAttributeVisitor( 598 new ParameterShrinker(methodRemovalParameterCounter)))); 599 } 600 else if (codeRemovalAdvanced) 601 { 602 // Just update the local variable frame sizes. 603 programClassPool.classesAccept( 604 new AllMethodVisitor( 605 new AllAttributeVisitor( 606 new StackSizeUpdater()))); 607 } 608 609 if (methodRemovalParameter && 610 methodRemovalParameterCounter.getCount() > 0) 611 { 612 // Tweak the descriptors of duplicate initializers, due to removed 613 // method parameters. 614 programClassPool.classesAccept( 615 new AllMethodVisitor( 616 new DuplicateInitializerFixer(initializerFixCounter1))); 617 618 if (initializerFixCounter1.getCount() > 0) 619 { 620 // Fix all invocations of tweaked initializers. 621 programClassPool.classesAccept( 622 new AllMethodVisitor( 623 new AllAttributeVisitor( 624 new DuplicateInitializerInvocationFixer(addedCounter)))); 625 626 // Fix all references to tweaked initializers. 627 programClassPool.classesAccept(new MemberReferenceFixer()); 628 } 629 } 630 631 //// Specializing the class member descriptors seems to increase the 632 //// class file size, on average. 633 //// Specialize all class member descriptors. 634 //programClassPool.classesAccept(new AllMemberVisitor( 635 // new OptimizationInfoMemberFilter( 636 // new MemberDescriptorSpecializer()))); 637 // 638 //// Fix all references to classes, for MemberDescriptorSpecializer. 639 //programClassPool.classesAccept(new AllMemberVisitor( 640 // new OptimizationInfoMemberFilter( 641 // new ClassReferenceFixer(true)))); 642 643 // Mark all classes with package visible members. 644 // Mark all exception catches of methods. 645 // Count all method invocations. 646 // Mark super invocations and other access of methods. 647 programClassPool.classesAccept( 648 new MultiClassVisitor( 649 new ClassVisitor[] 650 { 651 new PackageVisibleMemberContainingClassMarker(), 652 new AllConstantVisitor( 653 new PackageVisibleMemberInvokingClassMarker()), 654 new AllMethodVisitor( 655 new MultiMemberVisitor( 656 new MemberVisitor[] 657 { 658 new AllAttributeVisitor( 659 new MultiAttributeVisitor( 660 new AttributeVisitor[] 661 { 662 new CatchExceptionMarker(), 663 new AllInstructionVisitor( 664 new MultiInstructionVisitor( 665 new InstructionVisitor[] 666 { 667 new InstantiationClassMarker(), 668 new InstanceofClassMarker(), 669 new DotClassMarker(), 670 new MethodInvocationMarker(), 671 new SuperInvocationMarker(), 672 new DynamicInvocationMarker(), 673 new BackwardBranchMarker(), 674 new AccessMethodMarker(), 675 })), 676 new AllExceptionInfoVisitor( 677 new ExceptionHandlerConstantVisitor( 678 new ReferencedClassVisitor( 679 new CaughtClassMarker()))), 680 })), 681 })), 682 })); 683 684 if (classMergingVertical) 685 { 686 // Merge subclasses up into their superclasses or 687 // merge interfaces down into their implementing classes. 688 programClassPool.classesAccept( 689 new VerticalClassMerger(configuration.allowAccessModification, 690 configuration.mergeInterfacesAggressively, 691 classMergingVerticalCounter)); 692 } 693 694 if (classMergingHorizontal) 695 { 696 // Merge classes into their sibling classes. 697 programClassPool.classesAccept( 698 new HorizontalClassMerger(configuration.allowAccessModification, 699 configuration.mergeInterfacesAggressively, 700 classMergingHorizontalCounter)); 701 } 702 703 if (classMergingVerticalCounter .getCount() > 0 || 704 classMergingHorizontalCounter.getCount() > 0) 705 { 706 // Clean up inner class attributes to avoid loops. 707 programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover()); 708 709 // Update references to merged classes. 710 programClassPool.classesAccept(new TargetClassChanger()); 711 programClassPool.classesAccept(new ClassReferenceFixer(true)); 712 programClassPool.classesAccept(new MemberReferenceFixer()); 713 714 if (configuration.allowAccessModification) 715 { 716 // Fix the access flags of referenced merged classes and their 717 // class members. 718 programClassPool.classesAccept( 719 new AccessFixer()); 720 } 721 722 // Fix the access flags of the inner classes information. 723 programClassPool.classesAccept( 724 new AllAttributeVisitor( 725 new AllInnerClassesInfoVisitor( 726 new InnerClassesAccessFixer()))); 727 728 // Tweak the descriptors of duplicate initializers, due to merged 729 // parameter classes. 730 programClassPool.classesAccept( 731 new AllMethodVisitor( 732 new DuplicateInitializerFixer(initializerFixCounter2))); 733 734 if (initializerFixCounter2.getCount() > 0) 735 { 736 // Fix all invocations of tweaked initializers. 737 programClassPool.classesAccept( 738 new AllMethodVisitor( 739 new AllAttributeVisitor( 740 new DuplicateInitializerInvocationFixer(addedCounter)))); 741 742 // Fix all references to tweaked initializers. 743 programClassPool.classesAccept(new MemberReferenceFixer()); 744 } 745 } 746 747 if (methodInliningUnique) 748 { 749 // Inline methods that are only invoked once. 750 programClassPool.classesAccept( 751 new AllMethodVisitor( 752 new AllAttributeVisitor( 753 new MethodInliner(configuration.microEdition, 754 configuration.allowAccessModification, 755 true, 756 methodInliningUniqueCounter)))); 757 } 758 759 if (methodInliningShort) 760 { 761 // Inline short methods. 762 programClassPool.classesAccept( 763 new AllMethodVisitor( 764 new AllAttributeVisitor( 765 new MethodInliner(configuration.microEdition, 766 configuration.allowAccessModification, 767 false, 768 methodInliningShortCounter)))); 769 } 770 771 if (methodInliningTailrecursion) 772 { 773 // Simplify tail recursion calls. 774 programClassPool.classesAccept( 775 new AllMethodVisitor( 776 new AllAttributeVisitor( 777 new TailRecursionSimplifier(methodInliningTailrecursionCounter)))); 778 } 779 780 if (fieldMarkingPrivate || 781 methodMarkingPrivate) 782 { 783 // Mark all class members that can not be made private. 784 programClassPool.classesAccept( 785 new NonPrivateMemberMarker()); 786 } 787 788 if (fieldMarkingPrivate) 789 { 790 // Make all non-private fields private, whereever possible. 791 programClassPool.classesAccept( 792 new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE, 793 new AllFieldVisitor( 794 new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE, 795 new MemberPrivatizer(fieldMarkingPrivateCounter))))); 796 } 797 798 if (methodMarkingPrivate) 799 { 800 // Make all non-private methods private, whereever possible. 801 programClassPool.classesAccept( 802 new ClassAccessFilter(0, ClassConstants.ACC_INTERFACE, 803 new AllMethodVisitor( 804 new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE, 805 new MemberPrivatizer(methodMarkingPrivateCounter))))); 806 } 807 808 if ((methodInliningUniqueCounter .getCount() > 0 || 809 methodInliningShortCounter .getCount() > 0 || 810 methodInliningTailrecursionCounter.getCount() > 0) && 811 configuration.allowAccessModification) 812 { 813 // Fix the access flags of referenced classes and class members, 814 // for MethodInliner. 815 programClassPool.classesAccept( 816 new AccessFixer()); 817 } 818 819 if (methodRemovalParameterCounter .getCount() > 0 || 820 classMergingVerticalCounter .getCount() > 0 || 821 classMergingHorizontalCounter .getCount() > 0 || 822 methodMarkingPrivateCounter .getCount() > 0 ) 823 { 824 // Fix invocations of interface methods, of methods that have become 825 // non-abstract or private, and of methods that have moved to a 826 // different package. 827 programClassPool.classesAccept( 828 new AllMemberVisitor( 829 new AllAttributeVisitor( 830 new MethodInvocationFixer()))); 831 } 832 833 if (codeMerging) 834 { 835 // Share common blocks of code at branches. 836 programClassPool.classesAccept( 837 new AllMethodVisitor( 838 new AllAttributeVisitor( 839 new GotoCommonCodeReplacer(codeMergingCounter)))); 840 } 841 842 // Create a branch target marker and a code attribute editor that can 843 // be reused for all code attributes. 844 BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); 845 CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 846 847 List peepholeOptimizations = new ArrayList(); 848 if (codeSimplificationVariable) 849 { 850 // Peephole optimizations involving local variables. 851 peepholeOptimizations.add( 852 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 853 InstructionSequenceConstants.VARIABLE, 854 branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter)); 855 } 856 857 if (codeSimplificationArithmetic) 858 { 859 // Peephole optimizations involving arithmetic operations. 860 peepholeOptimizations.add( 861 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 862 InstructionSequenceConstants.ARITHMETIC, 863 branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter)); 864 } 865 866 if (codeSimplificationCast) 867 { 868 // Peephole optimizations involving cast operations. 869 peepholeOptimizations.add( 870 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 871 InstructionSequenceConstants.CAST, 872 branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter)); 873 } 874 875 if (codeSimplificationField) 876 { 877 // Peephole optimizations involving fields. 878 peepholeOptimizations.add( 879 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 880 InstructionSequenceConstants.FIELD, 881 branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter)); 882 } 883 884 if (codeSimplificationBranch) 885 { 886 // Peephole optimizations involving branches. 887 peepholeOptimizations.add( 888 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 889 InstructionSequenceConstants.BRANCH, 890 branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter)); 891 892 // Include optimization of branches to branches and returns. 893 peepholeOptimizations.add( 894 new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); 895 peepholeOptimizations.add( 896 new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); 897 } 898 899 if (codeSimplificationString) 900 { 901 // Peephole optimizations involving branches. 902 peepholeOptimizations.add( 903 new InstructionSequencesReplacer(InstructionSequenceConstants.CONSTANTS, 904 InstructionSequenceConstants.STRING, 905 branchTargetFinder, codeAttributeEditor, codeSimplificationStringCounter)); 906 } 907 908 if (!peepholeOptimizations.isEmpty()) 909 { 910 // Convert the list into an array. 911 InstructionVisitor[] peepholeOptimizationsArray = 912 new InstructionVisitor[peepholeOptimizations.size()]; 913 peepholeOptimizations.toArray(peepholeOptimizationsArray); 914 915 // Perform the peephole optimisations. 916 programClassPool.classesAccept( 917 new AllMethodVisitor( 918 new AllAttributeVisitor( 919 new PeepholeOptimizer(branchTargetFinder, codeAttributeEditor, 920 new MultiInstructionVisitor( 921 peepholeOptimizationsArray))))); 922 } 923 924 if (codeRemovalException) 925 { 926 // Remove unnecessary exception handlers. 927 programClassPool.classesAccept( 928 new AllMethodVisitor( 929 new AllAttributeVisitor( 930 new UnreachableExceptionRemover(codeRemovalExceptionCounter)))); 931 } 932 933 if (codeRemovalSimple) 934 { 935 // Remove unreachable code. 936 programClassPool.classesAccept( 937 new AllMethodVisitor( 938 new AllAttributeVisitor( 939 new UnreachableCodeRemover(deletedCounter)))); 940 } 941 942 if (codeRemovalVariable) 943 { 944 // Remove all unused local variables. 945 programClassPool.classesAccept( 946 new AllMethodVisitor( 947 new AllAttributeVisitor( 948 new VariableShrinker(codeRemovalVariableCounter)))); 949 } 950 951 if (codeAllocationVariable) 952 { 953 // Optimize the variables. 954 programClassPool.classesAccept( 955 new AllMethodVisitor( 956 new AllAttributeVisitor( 957 new VariableOptimizer(false, codeAllocationVariableCounter)))); 958 } 959 960 961 // Remove unused constants. 962 programClassPool.classesAccept( 963 new ConstantPoolShrinker()); 964 965 int classMarkingFinalCount = classMarkingFinalCounter .getCount(); 966 int classUnboxingEnumCount = classUnboxingEnumCounter .getCount(); 967 int classMergingVerticalCount = classMergingVerticalCounter .getCount(); 968 int classMergingHorizontalCount = classMergingHorizontalCounter .getCount(); 969 int fieldRemovalWriteonlyCount = fieldRemovalWriteonlyCounter .getCount(); 970 int fieldMarkingPrivateCount = fieldMarkingPrivateCounter .getCount(); 971 int fieldPropagationValueCount = fieldPropagationValueCounter .getCount(); 972 int methodMarkingPrivateCount = methodMarkingPrivateCounter .getCount(); 973 int methodMarkingStaticCount = methodMarkingStaticCounter .getCount(); 974 int methodMarkingFinalCount = methodMarkingFinalCounter .getCount(); 975 int methodRemovalParameterCount = methodRemovalParameterCounter .getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount(); 976 int methodPropagationParameterCount = methodPropagationParameterCounter .getCount(); 977 int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount(); 978 int methodInliningShortCount = methodInliningShortCounter .getCount(); 979 int methodInliningUniqueCount = methodInliningUniqueCounter .getCount(); 980 int methodInliningTailrecursionCount = methodInliningTailrecursionCounter .getCount(); 981 int codeMergingCount = codeMergingCounter .getCount(); 982 int codeSimplificationVariableCount = codeSimplificationVariableCounter .getCount(); 983 int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter.getCount(); 984 int codeSimplificationCastCount = codeSimplificationCastCounter .getCount(); 985 int codeSimplificationFieldCount = codeSimplificationFieldCounter .getCount(); 986 int codeSimplificationBranchCount = codeSimplificationBranchCounter .getCount(); 987 int codeSimplificationStringCount = codeSimplificationStringCounter .getCount(); 988 int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter .getCount(); 989 int codeRemovalCount = deletedCounter .getCount() - addedCounter.getCount(); 990 int codeRemovalVariableCount = codeRemovalVariableCounter .getCount(); 991 int codeRemovalExceptionCount = codeRemovalExceptionCounter .getCount(); 992 int codeAllocationVariableCount = codeAllocationVariableCounter .getCount(); 993 994 // Forget about constant fields, parameters, and return values, if they 995 // didn't lead to any useful optimizations. We want to avoid fruitless 996 // additional optimization passes. 997 if (codeSimplificationAdvancedCount == 0) 998 { 999 fieldPropagationValueCount = 0; 1000 methodPropagationParameterCount = 0; 1001 methodPropagationReturnvalueCount = 0; 1002 } 1003 1004 if (configuration.verbose) 1005 { 1006 System.out.println(" Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal)); 1007 System.out.println(" Number of unboxed enum classes: " + classUnboxingEnumCount + disabled(classUnboxingEnum)); 1008 System.out.println(" Number of vertically merged classes: " + classMergingVerticalCount + disabled(classMergingVertical)); 1009 System.out.println(" Number of horizontally merged classes: " + classMergingHorizontalCount + disabled(classMergingHorizontal)); 1010 System.out.println(" Number of removed write-only fields: " + fieldRemovalWriteonlyCount + disabled(fieldRemovalWriteonly)); 1011 System.out.println(" Number of privatized fields: " + fieldMarkingPrivateCount + disabled(fieldMarkingPrivate)); 1012 System.out.println(" Number of inlined constant fields: " + fieldPropagationValueCount + disabled(fieldPropagationValue)); 1013 System.out.println(" Number of privatized methods: " + methodMarkingPrivateCount + disabled(methodMarkingPrivate)); 1014 System.out.println(" Number of staticized methods: " + methodMarkingStaticCount + disabled(methodMarkingStatic)); 1015 System.out.println(" Number of finalized methods: " + methodMarkingFinalCount + disabled(methodMarkingFinal)); 1016 System.out.println(" Number of removed method parameters: " + methodRemovalParameterCount + disabled(methodRemovalParameter)); 1017 System.out.println(" Number of inlined constant parameters: " + methodPropagationParameterCount + disabled(methodPropagationParameter)); 1018 System.out.println(" Number of inlined constant return values: " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue)); 1019 System.out.println(" Number of inlined short method calls: " + methodInliningShortCount + disabled(methodInliningShort)); 1020 System.out.println(" Number of inlined unique method calls: " + methodInliningUniqueCount + disabled(methodInliningUnique)); 1021 System.out.println(" Number of inlined tail recursion calls: " + methodInliningTailrecursionCount + disabled(methodInliningTailrecursion)); 1022 System.out.println(" Number of merged code blocks: " + codeMergingCount + disabled(codeMerging)); 1023 System.out.println(" Number of variable peephole optimizations: " + codeSimplificationVariableCount + disabled(codeSimplificationVariable)); 1024 System.out.println(" Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic)); 1025 System.out.println(" Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast)); 1026 System.out.println(" Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField)); 1027 System.out.println(" Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch)); 1028 System.out.println(" Number of string peephole optimizations: " + codeSimplificationStringCount + disabled(codeSimplificationString)); 1029 System.out.println(" Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced)); 1030 System.out.println(" Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced)); 1031 System.out.println(" Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable)); 1032 System.out.println(" Number of removed exception blocks: " + codeRemovalExceptionCount + disabled(codeRemovalException)); 1033 System.out.println(" Number of optimized local variable frames: " + codeAllocationVariableCount + disabled(codeAllocationVariable)); 1034 } 1035 1036 return classMarkingFinalCount > 0 || 1037 classUnboxingEnumCount > 0 || 1038 classMergingVerticalCount > 0 || 1039 classMergingHorizontalCount > 0 || 1040 fieldRemovalWriteonlyCount > 0 || 1041 fieldMarkingPrivateCount > 0 || 1042 methodMarkingPrivateCount > 0 || 1043 methodMarkingStaticCount > 0 || 1044 methodMarkingFinalCount > 0 || 1045 fieldPropagationValueCount > 0 || 1046 methodRemovalParameterCount > 0 || 1047 methodPropagationParameterCount > 0 || 1048 methodPropagationReturnvalueCount > 0 || 1049 methodInliningShortCount > 0 || 1050 methodInliningUniqueCount > 0 || 1051 methodInliningTailrecursionCount > 0 || 1052 codeMergingCount > 0 || 1053 codeSimplificationVariableCount > 0 || 1054 codeSimplificationArithmeticCount > 0 || 1055 codeSimplificationCastCount > 0 || 1056 codeSimplificationFieldCount > 0 || 1057 codeSimplificationBranchCount > 0 || 1058 codeSimplificationStringCount > 0 || 1059 codeSimplificationAdvancedCount > 0 || 1060 codeRemovalCount > 0 || 1061 codeRemovalVariableCount > 0 || 1062 codeRemovalExceptionCount > 0 || 1063 codeAllocationVariableCount > 0; 1064 } 1065 1066 1067 /** 1068 * Returns a String indicating whether the given flag is enabled or 1069 * disabled. 1070 */ 1071 private String disabled(boolean flag) 1072 { 1073 return flag ? "" : " (disabled)"; 1074 } 1075 1076 1077 /** 1078 * Returns a String indicating whether the given flags are enabled or 1079 * disabled. 1080 */ 1081 private String disabled(boolean flag1, boolean flag2) 1082 { 1083 return flag1 && flag2 ? "" : 1084 flag1 || flag2 ? " (partially disabled)" : 1085 " (disabled)"; 1086 } 1087} 1088