/** * Prints out the seeds for the classes in the given program class pool. * * @param configuration the configuration containing the keep options. * @throws IOException if an IO error occurs while writing the configuration. */ public void write( Configuration configuration, ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some keep commands. if (configuration.keep == null) { throw new IOException("You have to specify '-keep' options for the shrinking step."); } // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // Create a visitor for printing out the seeds. We're printing out // the program elements that are preserved against shrinking, // optimization, or obfuscation. KeepMarker keepMarker = new KeepMarker(); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor( configuration.keep, keepMarker, keepMarker, true, true, true); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // Print out the seeds. SimpleClassPrinter printer = new SimpleClassPrinter(false, ps); programClassPool.classesAcceptAlphabetically( new MultiClassVisitor( new ClassVisitor[] { new KeptClassFilter(printer), new AllMemberVisitor(new KeptMemberFilter(printer)) })); }
/** Prints out the contents of the program classes. */ private void dump() throws IOException { if (configuration.verbose) { System.out.println("Printing classes to [" + fileName(configuration.dump) + "]..."); } PrintStream ps = createPrintStream(configuration.dump); try { programClassPool.classesAccept(new ClassPrinter(ps)); } finally { closePrintStream(ps); } }
/** Performs obfuscation of the given program class pool. */ public void execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some keep commands. if (configuration.keep == null && configuration.applyMapping == null && configuration.printMapping == null) { throw new IOException("You have to specify '-keep' options for the obfuscation step."); } // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // If the class member names have to correspond globally, // link all class members in all classes, otherwise // link all non-private methods in all class hierarchies. ClassVisitor memberInfoLinker = configuration.useUniqueClassMemberNames ? (ClassVisitor) new AllMemberVisitor(new MethodLinker()) : (ClassVisitor) new BottomClassFilter(new MethodLinker()); programClassPool.classesAccept(memberInfoLinker); libraryClassPool.classesAccept(memberInfoLinker); // Create a visitor for marking the seeds. NameMarker nameMarker = new NameMarker(); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor( configuration.keep, nameMarker, nameMarker, false, false, true); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // All library classes and library class members keep their names. libraryClassPool.classesAccept(nameMarker); libraryClassPool.classesAccept(new AllMemberVisitor(nameMarker)); // Mark attributes that have to be kept. AttributeUsageMarker requiredAttributeUsageMarker = new AttributeUsageMarker(); AttributeVisitor optionalAttributeUsageMarker = configuration.keepAttributes == null ? null : new AttributeNameFilter( new ListParser(new NameParser()).parse(configuration.keepAttributes), requiredAttributeUsageMarker); programClassPool.classesAccept( new AllAttributeVisitor( true, new RequiredAttributeFilter( requiredAttributeUsageMarker, optionalAttributeUsageMarker))); // Remove the attributes that can be discarded. Note that the attributes // may only be discarded after the seeds have been marked, since the // configuration may rely on annotations. programClassPool.classesAccept(new AttributeShrinker()); // Apply the mapping, if one has been specified. The mapping can // override the names of library classes and of library class members. if (configuration.applyMapping != null) { WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); MappingReader reader = new MappingReader(configuration.applyMapping); MappingProcessor keeper = new MultiMappingProcessor( new MappingProcessor[] { new MappingKeeper(programClassPool, warningPrinter), new MappingKeeper(libraryClassPool, null), }); reader.pump(keeper); // Print out a summary of the warnings if necessary. int mappingWarningCount = warningPrinter.getWarningCount(); if (mappingWarningCount > 0) { System.err.println( "Warning: there were " + mappingWarningCount + " kept classes and class members that were remapped anyway."); System.err.println( " You should adapt your configuration or edit the mapping file."); if (!configuration.ignoreWarnings) { System.err.println(" If you are sure this remapping won't hurt,"); System.err.println( " you could try your luck using the '-ignorewarnings' option."); throw new IOException("Please correct the above warnings first."); } } } // Come up with new names for all classes. DictionaryNameFactory classNameFactory = configuration.classObfuscationDictionary != null ? new DictionaryNameFactory(configuration.classObfuscationDictionary, null) : null; DictionaryNameFactory packageNameFactory = configuration.packageObfuscationDictionary != null ? new DictionaryNameFactory(configuration.packageObfuscationDictionary, null) : null; programClassPool.classesAccept( new ClassObfuscator( programClassPool, classNameFactory, packageNameFactory, configuration.useMixedCaseClassNames, configuration.keepPackageNames, configuration.flattenPackageHierarchy, configuration.repackageClasses, configuration.allowAccessModification)); // Come up with new names for all class members. NameFactory nameFactory = new SimpleNameFactory(); if (configuration.obfuscationDictionary != null) { nameFactory = new DictionaryNameFactory(configuration.obfuscationDictionary, nameFactory); } WarningPrinter warningPrinter = new WarningPrinter(System.err, configuration.warn); // Maintain a map of names to avoid [descriptor - new name - old name]. Map descriptorMap = new HashMap(); // Do the class member names have to be globally unique? if (configuration.useUniqueClassMemberNames) { // Collect all member names in all classes. programClassPool.classesAccept( new AllMemberVisitor( new MemberNameCollector(configuration.overloadAggressively, descriptorMap))); // Assign new names to all members in all classes. programClassPool.classesAccept( new AllMemberVisitor( new MemberObfuscator( configuration.overloadAggressively, nameFactory, descriptorMap))); } else { // Come up with new names for all non-private class members. programClassPool.classesAccept( new MultiClassVisitor( new ClassVisitor[] { // Collect all private member names in this class and down // the hierarchy. new ClassHierarchyTraveler( true, false, false, true, new AllMemberVisitor( new MemberAccessFilter( ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberNameCollector( configuration.overloadAggressively, descriptorMap)))), // Collect all non-private member names anywhere in the hierarchy. new ClassHierarchyTraveler( true, true, true, true, new AllMemberVisitor( new MemberAccessFilter( 0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector( configuration.overloadAggressively, descriptorMap)))), // Assign new names to all non-private members in this class. new AllMemberVisitor( new MemberAccessFilter( 0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberObfuscator( configuration.overloadAggressively, nameFactory, descriptorMap))), // Clear the collected names. new MapCleaner(descriptorMap) })); // Come up with new names for all private class members. programClassPool.classesAccept( new MultiClassVisitor( new ClassVisitor[] { // Collect all member names in this class. new AllMemberVisitor( new MemberNameCollector(configuration.overloadAggressively, descriptorMap)), // Collect all non-private member names higher up the hierarchy. new ClassHierarchyTraveler( false, true, true, false, new AllMemberVisitor( new MemberAccessFilter( 0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector( configuration.overloadAggressively, descriptorMap)))), // Assign new names to all private members in this class. new AllMemberVisitor( new MemberAccessFilter( ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberObfuscator( configuration.overloadAggressively, nameFactory, descriptorMap))), // Clear the collected names. new MapCleaner(descriptorMap) })); } // Some class members may have ended up with conflicting names. // Come up with new, globally unique names for them. NameFactory specialNameFactory = new SpecialNameFactory(new SimpleNameFactory()); // Collect a map of special names to avoid // [descriptor - new name - old name]. Map specialDescriptorMap = new HashMap(); programClassPool.classesAccept( new AllMemberVisitor( new MemberSpecialNameFilter( new MemberNameCollector( configuration.overloadAggressively, specialDescriptorMap)))); libraryClassPool.classesAccept( new AllMemberVisitor( new MemberSpecialNameFilter( new MemberNameCollector( configuration.overloadAggressively, specialDescriptorMap)))); // Replace conflicting non-private member names with special names. programClassPool.classesAccept( new MultiClassVisitor( new ClassVisitor[] { // Collect all private member names in this class and down // the hierarchy. new ClassHierarchyTraveler( true, false, false, true, new AllMemberVisitor( new MemberAccessFilter( ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberNameCollector( configuration.overloadAggressively, descriptorMap)))), // Collect all non-private member names in this class and // higher up the hierarchy. new ClassHierarchyTraveler( true, true, true, false, new AllMemberVisitor( new MemberAccessFilter( 0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector( configuration.overloadAggressively, descriptorMap)))), // Assign new names to all conflicting non-private members // in this class and higher up the hierarchy. new ClassHierarchyTraveler( true, true, true, false, new AllMemberVisitor( new MemberAccessFilter( 0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameConflictFixer( configuration.overloadAggressively, descriptorMap, warningPrinter, new MemberObfuscator( configuration.overloadAggressively, specialNameFactory, specialDescriptorMap))))), // Clear the collected names. new MapCleaner(descriptorMap) })); // Replace conflicting private member names with special names. // This is only possible if those names were kept or mapped. programClassPool.classesAccept( new MultiClassVisitor( new ClassVisitor[] { // Collect all member names in this class. new AllMemberVisitor( new MemberNameCollector(configuration.overloadAggressively, descriptorMap)), // Collect all non-private member names higher up the hierarchy. new ClassHierarchyTraveler( false, true, true, false, new AllMemberVisitor( new MemberAccessFilter( 0, ClassConstants.INTERNAL_ACC_PRIVATE, new MemberNameCollector( configuration.overloadAggressively, descriptorMap)))), // Assign new names to all conflicting private members in this // class. new AllMemberVisitor( new MemberAccessFilter( ClassConstants.INTERNAL_ACC_PRIVATE, 0, new MemberNameConflictFixer( configuration.overloadAggressively, descriptorMap, warningPrinter, new MemberObfuscator( configuration.overloadAggressively, specialNameFactory, specialDescriptorMap)))), // Clear the collected names. new MapCleaner(descriptorMap) })); // Print out any warnings about member name conflicts. int warningCount = warningPrinter.getWarningCount(); if (warningCount > 0) { System.err.println( "Warning: there were " + warningCount + " conflicting class member name mappings."); System.err.println(" Your configuration may be inconsistent."); if (!configuration.ignoreWarnings) { System.err.println(" If you are sure the conflicts are harmless,"); System.err.println(" you could try your luck using the '-ignorewarnings' option."); throw new IOException("Please correct the above warnings first."); } } // Print out the mapping, if requested. if (configuration.printMapping != null) { PrintStream ps = isFile(configuration.printMapping) ? new PrintStream( new BufferedOutputStream(new FileOutputStream(configuration.printMapping))) : System.out; // Print out items that will be removed. programClassPool.classesAcceptAlphabetically(new MappingPrinter(ps)); if (ps != System.out) { ps.close(); } } // Actually apply the new names. programClassPool.classesAccept(new ClassRenamer()); libraryClassPool.classesAccept(new ClassRenamer()); // Update all references to these new names. programClassPool.classesAccept(new ClassReferenceFixer(false)); libraryClassPool.classesAccept(new ClassReferenceFixer(false)); programClassPool.classesAccept(new MemberReferenceFixer()); // Make package visible elements public or protected, if obfuscated // classes are being repackaged aggressively. if (configuration.repackageClasses != null && configuration.allowAccessModification) { programClassPool.classesAccept(new AllConstantVisitor(new AccessFixer())); } // Rename the source file attributes, if requested. if (configuration.newSourceFileAttribute != null) { programClassPool.classesAccept(new SourceFileRenamer(configuration.newSourceFileAttribute)); } // Mark NameAndType constant pool entries that have to be kept // and remove the other ones. programClassPool.classesAccept(new NameAndTypeUsageMarker()); programClassPool.classesAccept(new NameAndTypeShrinker()); // Mark Utf8 constant pool entries that have to be kept // and remove the other ones. programClassPool.classesAccept(new Utf8UsageMarker()); programClassPool.classesAccept(new Utf8Shrinker()); }
/** * Initializes the classes in the given program class pool and library class pool, performs some * basic checks, and shrinks the library class pool. */ public void execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { int originalLibraryClassPoolSize = libraryClassPool.size(); // Perform a basic check on the keep options in the configuration. WarningPrinter keepClassMemberNotePrinter = new WarningPrinter(System.out, configuration.note); new KeepClassMemberChecker(keepClassMemberNotePrinter) .checkClassSpecifications(configuration.keep); // Construct a reduced library class pool with only those library // classes whose hierarchies are referenced by the program classes. // We can't do this if we later have to come up with the obfuscated // class member names that are globally unique. ClassPool reducedLibraryClassPool = configuration.useUniqueClassMemberNames ? null : new ClassPool(); WarningPrinter classReferenceWarningPrinter = new WarningPrinter(System.err, configuration.warn); WarningPrinter dependencyWarningPrinter = new WarningPrinter(System.err, configuration.warn); // Initialize the superclass hierarchies for program classes. programClassPool.classesAccept( new ClassSuperHierarchyInitializer( programClassPool, libraryClassPool, classReferenceWarningPrinter, null)); // Initialize the superclass hierarchy of all library classes, without // warnings. libraryClassPool.classesAccept( new ClassSuperHierarchyInitializer( programClassPool, libraryClassPool, null, dependencyWarningPrinter)); // Initialize the class references of program class members and // attributes. Note that all superclass hierarchies have to be // initialized for this purpose. WarningPrinter memberReferenceWarningPrinter = new WarningPrinter(System.err, configuration.warn); programClassPool.classesAccept( new ClassReferenceInitializer( programClassPool, libraryClassPool, classReferenceWarningPrinter, memberReferenceWarningPrinter, null)); if (reducedLibraryClassPool != null) { // Collect the library classes that are directly referenced by // program classes, without introspection. programClassPool.classesAccept( new ReferencedClassVisitor( new LibraryClassFilter(new ClassPoolFiller(reducedLibraryClassPool)))); // Reinitialize the superclass hierarchies of referenced library // classes, this time with warnings. reducedLibraryClassPool.classesAccept( new ClassSuperHierarchyInitializer( programClassPool, libraryClassPool, classReferenceWarningPrinter, null)); } // Initialize the Class.forName references. WarningPrinter dynamicClassReferenceNotePrinter = new WarningPrinter(System.out, configuration.note); WarningPrinter classForNameNotePrinter = new WarningPrinter(System.out, configuration.note); programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new AllInstructionVisitor( new DynamicClassReferenceInitializer( programClassPool, libraryClassPool, dynamicClassReferenceNotePrinter, null, classForNameNotePrinter, createClassNoteExceptionMatcher(configuration.keep)))))); // Initialize the Class.get[Declared]{Field,Method} references. WarningPrinter getMemberNotePrinter = new WarningPrinter(System.out, configuration.note); programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new AllInstructionVisitor( new DynamicMemberReferenceInitializer( programClassPool, libraryClassPool, getMemberNotePrinter, createClassMemberNoteExceptionMatcher(configuration.keep, true), createClassMemberNoteExceptionMatcher(configuration.keep, false)))))); // Initialize other string constant references, if requested. if (configuration.adaptClassStrings != null) { programClassPool.classesAccept( new ClassNameFilter( configuration.adaptClassStrings, new AllConstantVisitor( new StringReferenceInitializer(programClassPool, libraryClassPool)))); } // Print various notes, if specified. WarningPrinter fullyQualifiedClassNameNotePrinter = new WarningPrinter(System.out, configuration.note); WarningPrinter descriptorKeepNotePrinter = new WarningPrinter(System.out, configuration.note); new FullyQualifiedClassNameChecker( programClassPool, libraryClassPool, fullyQualifiedClassNameNotePrinter) .checkClassSpecifications(configuration.keep); new DescriptorKeepChecker(programClassPool, libraryClassPool, descriptorKeepNotePrinter) .checkClassSpecifications(configuration.keep); // Initialize the class references of library class members. if (reducedLibraryClassPool != null) { // Collect the library classes that are referenced by program // classes, directly or indirectly, with or without introspection. programClassPool.classesAccept( new ReferencedClassVisitor( new LibraryClassFilter( new ClassHierarchyTraveler( true, true, true, false, new LibraryClassFilter(new ClassPoolFiller(reducedLibraryClassPool)))))); // Initialize the class references of referenced library // classes, without warnings. reducedLibraryClassPool.classesAccept( new ClassReferenceInitializer( programClassPool, libraryClassPool, null, null, dependencyWarningPrinter)); // Reset the library class pool. libraryClassPool.clear(); // Copy the library classes that are referenced directly by program // classes and the library classes that are referenced by referenced // library classes. reducedLibraryClassPool.classesAccept( new MultiClassVisitor( new ClassVisitor[] { new ClassHierarchyTraveler( true, true, true, false, new LibraryClassFilter(new ClassPoolFiller(libraryClassPool))), new ReferencedClassVisitor( new LibraryClassFilter( new ClassHierarchyTraveler( true, true, true, false, new LibraryClassFilter(new ClassPoolFiller(libraryClassPool))))) })); } else { // Initialize the class references of all library class members. libraryClassPool.classesAccept( new ClassReferenceInitializer( programClassPool, libraryClassPool, null, null, dependencyWarningPrinter)); } // Initialize the subclass hierarchies. programClassPool.classesAccept(new ClassSubHierarchyInitializer()); libraryClassPool.classesAccept(new ClassSubHierarchyInitializer()); // Share strings between the classes, to reduce heap memory usage. programClassPool.classesAccept(new StringSharer()); libraryClassPool.classesAccept(new StringSharer()); // Print out a summary of the notes, if necessary. int fullyQualifiedNoteCount = fullyQualifiedClassNameNotePrinter.getWarningCount(); if (fullyQualifiedNoteCount > 0) { System.out.println( "Note: there were " + fullyQualifiedNoteCount + " references to unknown classes."); System.out.println(" You should check your configuration for typos."); } int descriptorNoteCount = descriptorKeepNotePrinter.getWarningCount(); if (descriptorNoteCount > 0) { System.out.println( "Note: there were " + descriptorNoteCount + " unkept descriptor classes in kept class members."); System.out.println(" You should consider explicitly keeping the mentioned classes"); System.out.println(" (using '-keep')."); } int dynamicClassReferenceNoteCount = dynamicClassReferenceNotePrinter.getWarningCount(); if (dynamicClassReferenceNoteCount > 0) { System.out.println( "Note: there were " + dynamicClassReferenceNoteCount + " unresolved dynamic references to classes or interfaces."); System.err.println(" You should check if you need to specify additional program jars."); } int classForNameNoteCount = classForNameNotePrinter.getWarningCount(); if (classForNameNoteCount > 0) { System.out.println( "Note: there were " + classForNameNoteCount + " class casts of dynamically created class instances."); System.out.println( " You might consider explicitly keeping the mentioned classes and/or"); System.out.println(" their implementations (using '-keep')."); } int getmemberNoteCount = getMemberNotePrinter.getWarningCount(); if (getmemberNoteCount > 0) { System.out.println( "Note: there were " + getmemberNoteCount + " accesses to class members by means of introspection."); System.out.println( " You should consider explicitly keeping the mentioned class members"); System.out.println(" (using '-keep' or '-keepclassmembers')."); } // Print out a summary of the warnings, if necessary. int classReferenceWarningCount = classReferenceWarningPrinter.getWarningCount(); if (classReferenceWarningCount > 0) { System.err.println( "Warning: there were " + classReferenceWarningCount + " unresolved references to classes or interfaces."); System.err.println( " You may need to specify additional library jars (using '-libraryjars')."); if (configuration.skipNonPublicLibraryClasses) { System.err.println( " You may also have to remove the option '-skipnonpubliclibraryclasses'."); } } int dependencyWarningCount = dependencyWarningPrinter.getWarningCount(); if (dependencyWarningCount > 0) { System.err.println( "Warning: there were " + dependencyWarningCount + " instances of library classes depending on program classes."); System.err.println( " You must avoid such dependencies, since the program classes will"); System.err.println(" be processed, while the library classes will remain unchanged."); } int memberReferenceWarningCount = memberReferenceWarningPrinter.getWarningCount(); if (memberReferenceWarningCount > 0) { System.err.println( "Warning: there were " + memberReferenceWarningCount + " unresolved references to program class members."); System.err.println(" Your input classes appear to be inconsistent."); System.err.println(" You may need to recompile them and try again."); System.err.println(" Alternatively, you may have to specify the option "); System.err.println(" '-dontskipnonpubliclibraryclassmembers'."); if (configuration.skipNonPublicLibraryClasses) { System.err.println( " You may also have to remove the option '-skipnonpubliclibraryclasses'."); } } if ((classReferenceWarningCount > 0 || dependencyWarningCount > 0 || memberReferenceWarningCount > 0) && !configuration.ignoreWarnings) { throw new IOException("Please correct the above warnings first."); } if ((configuration.note == null || !configuration.note.isEmpty()) && (configuration.warn != null && configuration.warn.isEmpty() || configuration.ignoreWarnings)) { System.out.println("Note: You're ignoring all warnings!"); } // Discard unused library classes. if (configuration.verbose) { System.out.println("Ignoring unused library classes..."); System.out.println(" Original number of library classes: " + originalLibraryClassPoolSize); System.out.println(" Final number of library classes: " + libraryClassPool.size()); } }
/** Sorts the elements of all program classes. */ private void sortClassElements() { programClassPool.classesAccept(new ClassElementSorter()); }
/** Performs optimization of the given program class pool. */ public boolean execute(ClassPool programClassPool, ClassPool libraryClassPool) throws IOException { // Check if we have at least some keep commands. if (configuration.keep == null && configuration.applyMapping == null && configuration.printMapping == null) { throw new IOException("You have to specify '-keep' options for the optimization step."); } // Create a matcher for filtering optimizations. StringMatcher filter = configuration.optimizations != null ? new ListParser(new NameParser()).parse(configuration.optimizations) : new ConstantMatcher(true); boolean classMarkingFinal = StringMatcherUtil.matchesString(filter, CLASS_MARKING_FINAL); boolean classUnboxingEnum = StringMatcherUtil.matchesString(filter, CLASS_UNBOXING_ENUM); boolean classMergingVertical = StringMatcherUtil.matchesString(filter, CLASS_MERGING_VERTICAL); boolean classMergingHorizontal = StringMatcherUtil.matchesString(filter, CLASS_MERGING_HORIZONTAL); boolean fieldRemovalWriteonly = StringMatcherUtil.matchesString(filter, FIELD_REMOVAL_WRITEONLY); boolean fieldMarkingPrivate = StringMatcherUtil.matchesString(filter, FIELD_MARKING_PRIVATE); boolean fieldPropagationValue = StringMatcherUtil.matchesString(filter, FIELD_PROPAGATION_VALUE); boolean methodMarkingPrivate = StringMatcherUtil.matchesString(filter, METHOD_MARKING_PRIVATE); boolean methodMarkingStatic = StringMatcherUtil.matchesString(filter, METHOD_MARKING_STATIC); boolean methodMarkingFinal = StringMatcherUtil.matchesString(filter, METHOD_MARKING_FINAL); boolean methodRemovalParameter = StringMatcherUtil.matchesString(filter, METHOD_REMOVAL_PARAMETER); boolean methodPropagationParameter = StringMatcherUtil.matchesString(filter, METHOD_PROPAGATION_PARAMETER); boolean methodPropagationReturnvalue = StringMatcherUtil.matchesString(filter, METHOD_PROPAGATION_RETURNVALUE); boolean methodInliningShort = StringMatcherUtil.matchesString(filter, METHOD_INLINING_SHORT); boolean methodInliningUnique = StringMatcherUtil.matchesString(filter, METHOD_INLINING_UNIQUE); boolean methodInliningTailrecursion = StringMatcherUtil.matchesString(filter, METHOD_INLINING_TAILRECURSION); boolean codeMerging = StringMatcherUtil.matchesString(filter, CODE_MERGING); boolean codeSimplificationVariable = StringMatcherUtil.matchesString(filter, CODE_SIMPLIFICATION_VARIABLE); boolean codeSimplificationArithmetic = StringMatcherUtil.matchesString(filter, CODE_SIMPLIFICATION_ARITHMETIC); boolean codeSimplificationCast = StringMatcherUtil.matchesString(filter, CODE_SIMPLIFICATION_CAST); boolean codeSimplificationField = StringMatcherUtil.matchesString(filter, CODE_SIMPLIFICATION_FIELD); boolean codeSimplificationBranch = StringMatcherUtil.matchesString(filter, CODE_SIMPLIFICATION_BRANCH); boolean codeSimplificationString = StringMatcherUtil.matchesString(filter, CODE_SIMPLIFICATION_STRING); boolean codeSimplificationAdvanced = StringMatcherUtil.matchesString(filter, CODE_SIMPLIFICATION_ADVANCED); boolean codeRemovalAdvanced = StringMatcherUtil.matchesString(filter, CODE_REMOVAL_ADVANCED); boolean codeRemovalSimple = StringMatcherUtil.matchesString(filter, CODE_REMOVAL_SIMPLE); boolean codeRemovalVariable = StringMatcherUtil.matchesString(filter, CODE_REMOVAL_VARIABLE); boolean codeRemovalException = StringMatcherUtil.matchesString(filter, CODE_REMOVAL_EXCEPTION); boolean codeAllocationVariable = StringMatcherUtil.matchesString(filter, CODE_ALLOCATION_VARIABLE); // Create counters to count the numbers of optimizations. ClassCounter classMarkingFinalCounter = new ClassCounter(); ClassCounter classUnboxingEnumCounter = new ClassCounter(); ClassCounter classMergingVerticalCounter = new ClassCounter(); ClassCounter classMergingHorizontalCounter = new ClassCounter(); MemberCounter fieldRemovalWriteonlyCounter = new MemberCounter(); MemberCounter fieldMarkingPrivateCounter = new MemberCounter(); MemberCounter fieldPropagationValueCounter = new MemberCounter(); MemberCounter methodMarkingPrivateCounter = new MemberCounter(); MemberCounter methodMarkingStaticCounter = new MemberCounter(); MemberCounter methodMarkingFinalCounter = new MemberCounter(); MemberCounter methodRemovalParameterCounter = new MemberCounter(); MemberCounter methodPropagationParameterCounter = new MemberCounter(); MemberCounter methodPropagationReturnvalueCounter = new MemberCounter(); InstructionCounter methodInliningShortCounter = new InstructionCounter(); InstructionCounter methodInliningUniqueCounter = new InstructionCounter(); InstructionCounter methodInliningTailrecursionCounter = new InstructionCounter(); InstructionCounter codeMergingCounter = new InstructionCounter(); InstructionCounter codeSimplificationVariableCounter = new InstructionCounter(); InstructionCounter codeSimplificationArithmeticCounter = new InstructionCounter(); InstructionCounter codeSimplificationCastCounter = new InstructionCounter(); InstructionCounter codeSimplificationFieldCounter = new InstructionCounter(); InstructionCounter codeSimplificationBranchCounter = new InstructionCounter(); InstructionCounter codeSimplificationStringCounter = new InstructionCounter(); InstructionCounter codeSimplificationAdvancedCounter = new InstructionCounter(); InstructionCounter deletedCounter = new InstructionCounter(); InstructionCounter addedCounter = new InstructionCounter(); MemberCounter codeRemovalVariableCounter = new MemberCounter(); ExceptionCounter codeRemovalExceptionCounter = new ExceptionCounter(); MemberCounter codeAllocationVariableCounter = new MemberCounter(); MemberCounter initializerFixCounter1 = new MemberCounter(); MemberCounter initializerFixCounter2 = new MemberCounter(); // Some optimizations are required by other optimizations. codeSimplificationAdvanced = codeSimplificationAdvanced || fieldPropagationValue || methodPropagationParameter || methodPropagationReturnvalue; codeRemovalAdvanced = codeRemovalAdvanced || fieldRemovalWriteonly || methodMarkingStatic || methodRemovalParameter; codeRemovalSimple = codeRemovalSimple || codeSimplificationBranch; codeRemovalException = codeRemovalException || codeRemovalAdvanced || codeRemovalSimple; // Clean up any old visitor info. programClassPool.classesAccept(new ClassCleaner()); libraryClassPool.classesAccept(new ClassCleaner()); // Link all methods that should get the same optimization info. programClassPool.classesAccept(new BottomClassFilter(new MethodLinker())); libraryClassPool.classesAccept(new BottomClassFilter(new MethodLinker())); // Create a visitor for marking the seeds. KeepMarker keepMarker = new KeepMarker(); ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor( configuration.keep, keepMarker, keepMarker, false, true, false); // Mark the seeds. programClassPool.accept(classPoolvisitor); libraryClassPool.accept(classPoolvisitor); // All library classes and library class members remain unchanged. libraryClassPool.classesAccept(keepMarker); libraryClassPool.classesAccept(new AllMemberVisitor(keepMarker)); // We also keep all classes that are involved in .class constructs. // We're not looking at enum classes though, so they can be simplified. programClassPool.classesAccept( new ClassAccessFilter( 0, ClassConstants.ACC_ENUM, new AllMethodVisitor( new AllAttributeVisitor( new AllInstructionVisitor(new DotClassClassVisitor(keepMarker)))))); // We also keep all classes that are accessed dynamically. programClassPool.classesAccept( new AllConstantVisitor( new ConstantTagFilter( ClassConstants.CONSTANT_String, new ReferencedClassVisitor(keepMarker)))); // We also keep all class members that are accessed dynamically. programClassPool.classesAccept( new AllConstantVisitor( new ConstantTagFilter( ClassConstants.CONSTANT_String, new ReferencedMemberVisitor(keepMarker)))); // We also keep all bootstrap method signatures. programClassPool.classesAccept( new ClassVersionFilter( ClassConstants.CLASS_VERSION_1_7, new AllAttributeVisitor( new AttributeNameFilter( ClassConstants.ATTR_BootstrapMethods, new AllBootstrapMethodInfoVisitor( new BootstrapMethodHandleTraveler( new MethodrefTraveler(new ReferencedMemberVisitor(keepMarker)))))))); // We also keep all bootstrap method arguments that point to methods. // These arguments are typically the method handles for // java.lang.invoke.LambdaMetafactory#metafactory, which provides the // implementations for closures. programClassPool.classesAccept( new ClassVersionFilter( ClassConstants.CLASS_VERSION_1_7, new AllAttributeVisitor( new AttributeNameFilter( ClassConstants.ATTR_BootstrapMethods, new AllBootstrapMethodInfoVisitor( new BootstrapMethodArgumentVisitor( new MethodrefTraveler(new ReferencedMemberVisitor(keepMarker)))))))); // We also keep all classes (and their methods) returned by dynamic // method invocations. They may return dynamic implementations of // interfaces that otherwise appear unused. programClassPool.classesAccept( new ClassVersionFilter( ClassConstants.CLASS_VERSION_1_7, new AllConstantVisitor( new DynamicReturnedClassVisitor( new MultiClassVisitor( new ClassVisitor[] {keepMarker, new AllMemberVisitor(keepMarker)}))))); // Attach some optimization info to all classes and class members, so // it can be filled out later. programClassPool.classesAccept(new ClassOptimizationInfoSetter()); programClassPool.classesAccept(new AllMemberVisitor(new MemberOptimizationInfoSetter())); if (configuration.assumeNoSideEffects != null) { // Create a visitor for marking methods that don't have any side effects. NoSideEffectMethodMarker noSideEffectMethodMarker = new NoSideEffectMethodMarker(); ClassPoolVisitor noClassPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor( configuration.assumeNoSideEffects, null, noSideEffectMethodMarker); // Mark the seeds. programClassPool.accept(noClassPoolvisitor); libraryClassPool.accept(noClassPoolvisitor); } if (classMarkingFinal) { // Make classes final, whereever possible. programClassPool.classesAccept(new ClassFinalizer(classMarkingFinalCounter)); } if (methodMarkingFinal) { // Make methods final, whereever possible. programClassPool.classesAccept( new ClassAccessFilter( 0, ClassConstants.ACC_INTERFACE, new AllMethodVisitor(new MethodFinalizer(methodMarkingFinalCounter)))); } if (fieldRemovalWriteonly) { // Mark all fields that are write-only. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor(new AllInstructionVisitor(new ReadWriteFieldMarker())))); // Count the write-only fields. programClassPool.classesAccept( new AllFieldVisitor(new WriteOnlyFieldFilter(fieldRemovalWriteonlyCounter))); } else { // Mark all fields as read/write. programClassPool.classesAccept(new AllFieldVisitor(new ReadWriteFieldMarker())); } if (classUnboxingEnum) { ClassCounter counter = new ClassCounter(); // Mark all final enums that qualify as simple enums. programClassPool.classesAccept( new ClassAccessFilter( ClassConstants.ACC_FINAL | ClassConstants.ACC_ENUM, 0, new SimpleEnumClassChecker())); // Count the preliminary number of simple enums. programClassPool.classesAccept(new SimpleEnumFilter(counter)); // Only continue checking simple enums if there are any candidates. if (counter.getCount() > 0) { // Unmark all simple enums that are explicitly used as objects. programClassPool.classesAccept(new SimpleEnumUseChecker()); // Count the definitive number of simple enums. programClassPool.classesAccept(new SimpleEnumFilter(classUnboxingEnumCounter)); // Only start handling simple enums if there are any. if (classUnboxingEnumCounter.getCount() > 0) { // Simplify the use of the enum classes in code. programClassPool.classesAccept( new AllMethodVisitor(new AllAttributeVisitor(new SimpleEnumUseSimplifier()))); // Simplify the static initializers of simple enum classes. programClassPool.classesAccept(new SimpleEnumFilter(new SimpleEnumClassSimplifier())); // Simplify the use of the enum classes in descriptors. programClassPool.classesAccept(new SimpleEnumDescriptorSimplifier()); // Update references to class members with simple enum classes. programClassPool.classesAccept(new MemberReferenceFixer()); } } } // Mark all used parameters, including the 'this' parameters. programClassPool.classesAccept( new AllMethodVisitor( new OptimizationInfoMemberFilter( new ParameterUsageMarker(!methodMarkingStatic, !methodRemovalParameter)))); // Mark all classes that have static initializers. programClassPool.classesAccept(new StaticInitializerContainingClassMarker()); // Mark all methods that have side effects. programClassPool.accept(new SideEffectMethodMarker()); // System.out.println("Optimizer.execute: before evaluation simplification"); // programClassPool.classAccept("abc/Def", new NamedMethodVisitor("abc", null, new // ClassPrinter())); // Perform partial evaluation for filling out fields, method parameters, // and method return values, so they can be propagated. if (fieldPropagationValue || methodPropagationParameter || methodPropagationReturnvalue) { // We'll create values to be stored with fields, method parameters, // and return values. ValueFactory valueFactory = new ParticularValueFactory(); ValueFactory detailedValueFactory = new DetailedValueFactory(); InvocationUnit storingInvocationUnit = new StoringInvocationUnit( valueFactory, fieldPropagationValue, methodPropagationParameter, methodPropagationReturnvalue); // Evaluate synthetic classes in more detail, notably to propagate // the arrays of the classes generated for enum switch statements. programClassPool.classesAccept( new ClassAccessFilter( ClassConstants.ACC_SYNTHETIC, 0, new AllMethodVisitor( new AllAttributeVisitor( new PartialEvaluator(detailedValueFactory, storingInvocationUnit, false))))); // Evaluate non-synthetic classes. programClassPool.classesAccept( new ClassAccessFilter( 0, ClassConstants.ACC_SYNTHETIC, new AllMethodVisitor( new AllAttributeVisitor( new PartialEvaluator(valueFactory, storingInvocationUnit, false))))); if (fieldPropagationValue) { // Count the constant fields. programClassPool.classesAccept( new AllFieldVisitor(new ConstantMemberFilter(fieldPropagationValueCounter))); } if (methodPropagationParameter) { // Count the constant method parameters. programClassPool.classesAccept( new AllMethodVisitor(new ConstantParameterFilter(methodPropagationParameterCounter))); } if (methodPropagationReturnvalue) { // Count the constant method return values. programClassPool.classesAccept( new AllMethodVisitor(new ConstantMemberFilter(methodPropagationReturnvalueCounter))); } if (classUnboxingEnumCounter.getCount() > 0) { // Propagate the simple enum constant counts. programClassPool.classesAccept(new SimpleEnumFilter(new SimpleEnumArrayPropagator())); } if (codeSimplificationAdvanced) { // Fill out constants into the arrays of synthetic classes, // notably the arrays of the classes generated for enum switch // statements. InvocationUnit loadingInvocationUnit = new LoadingInvocationUnit( valueFactory, fieldPropagationValue, methodPropagationParameter, methodPropagationReturnvalue); programClassPool.classesAccept( new ClassAccessFilter( ClassConstants.ACC_SYNTHETIC, 0, new AllMethodVisitor( new AllAttributeVisitor( new PartialEvaluator(valueFactory, loadingInvocationUnit, false))))); } } // Perform partial evaluation again, now loading any previously stored // values for fields, method parameters, and method return values. ValueFactory valueFactory = new IdentifiedValueFactory(); InvocationUnit loadingInvocationUnit = new LoadingInvocationUnit( valueFactory, fieldPropagationValue, methodPropagationParameter, methodPropagationReturnvalue); if (codeSimplificationAdvanced) { // Simplify based on partial evaluation, propagating constant // field values, method parameter values, and return values. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new EvaluationSimplifier( new PartialEvaluator(valueFactory, loadingInvocationUnit, false), codeSimplificationAdvancedCounter)))); } if (codeRemovalAdvanced) { // Remove code based on partial evaluation, also removing unused // parameters from method invocations, and making methods static // if possible. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new EvaluationShrinker( new PartialEvaluator( valueFactory, loadingInvocationUnit, !codeSimplificationAdvanced), deletedCounter, addedCounter)))); } if (methodRemovalParameter) { // Shrink the parameters in the method descriptors. programClassPool.classesAccept( new AllMethodVisitor(new OptimizationInfoMemberFilter(new MethodDescriptorShrinker()))); } if (methodMarkingStatic) { // Make all non-static methods that don't require the 'this' // parameter static. programClassPool.classesAccept( new AllMethodVisitor( new OptimizationInfoMemberFilter( new MemberAccessFilter( 0, ClassConstants.ACC_STATIC, new MethodStaticizer(methodMarkingStaticCounter))))); } if (methodRemovalParameter) { // Fix all references to class members. // This operation also updates the stack sizes. programClassPool.classesAccept(new MemberReferenceFixer()); // Remove unused bootstrap method arguments. programClassPool.classesAccept( new AllAttributeVisitor( new AllBootstrapMethodInfoVisitor(new BootstrapMethodArgumentShrinker()))); } if (methodRemovalParameter || methodMarkingPrivate || methodMarkingStatic) { // Remove all unused parameters from the byte code, shifting all // remaining variables. // This operation also updates the local variable frame sizes. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor(new ParameterShrinker(methodRemovalParameterCounter)))); } else if (codeRemovalAdvanced) { // Just update the local variable frame sizes. programClassPool.classesAccept( new AllMethodVisitor(new AllAttributeVisitor(new StackSizeUpdater()))); } if (methodRemovalParameter && methodRemovalParameterCounter.getCount() > 0) { // Tweak the descriptors of duplicate initializers, due to removed // method parameters. programClassPool.classesAccept( new AllMethodVisitor(new DuplicateInitializerFixer(initializerFixCounter1))); if (initializerFixCounter1.getCount() > 0) { // Fix all invocations of tweaked initializers. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor(new DuplicateInitializerInvocationFixer(addedCounter)))); // Fix all references to tweaked initializers. programClassPool.classesAccept(new MemberReferenceFixer()); } } //// Specializing the class member descriptors seems to increase the //// class file size, on average. //// Specialize all class member descriptors. // programClassPool.classesAccept(new AllMemberVisitor( // new OptimizationInfoMemberFilter( // new MemberDescriptorSpecializer()))); // //// Fix all references to classes, for MemberDescriptorSpecializer. // programClassPool.classesAccept(new AllMemberVisitor( // new OptimizationInfoMemberFilter( // new ClassReferenceFixer(true)))); // Mark all classes with package visible members. // Mark all exception catches of methods. // Count all method invocations. // Mark super invocations and other access of methods. programClassPool.classesAccept( new MultiClassVisitor( new ClassVisitor[] { new PackageVisibleMemberContainingClassMarker(), new AllConstantVisitor(new PackageVisibleMemberInvokingClassMarker()), new AllMethodVisitor( new MultiMemberVisitor( new MemberVisitor[] { new AllAttributeVisitor( new MultiAttributeVisitor( new AttributeVisitor[] { new CatchExceptionMarker(), new AllInstructionVisitor( new MultiInstructionVisitor( new InstructionVisitor[] { new InstantiationClassMarker(), new InstanceofClassMarker(), new DotClassMarker(), new MethodInvocationMarker(), new SuperInvocationMarker(), new DynamicInvocationMarker(), new BackwardBranchMarker(), new AccessMethodMarker(), })), new AllExceptionInfoVisitor( new ExceptionHandlerConstantVisitor( new ReferencedClassVisitor(new CaughtClassMarker()))), })), })), })); if (classMergingVertical) { // Merge subclasses up into their superclasses or // merge interfaces down into their implementing classes. programClassPool.classesAccept( new VerticalClassMerger( configuration.allowAccessModification, configuration.mergeInterfacesAggressively, classMergingVerticalCounter)); } if (classMergingHorizontal) { // Merge classes into their sibling classes. programClassPool.classesAccept( new HorizontalClassMerger( configuration.allowAccessModification, configuration.mergeInterfacesAggressively, classMergingHorizontalCounter)); } if (classMergingVerticalCounter.getCount() > 0 || classMergingHorizontalCounter.getCount() > 0) { // Clean up inner class attributes to avoid loops. programClassPool.classesAccept(new RetargetedInnerClassAttributeRemover()); // Update references to merged classes. programClassPool.classesAccept(new TargetClassChanger()); programClassPool.classesAccept(new ClassReferenceFixer(true)); programClassPool.classesAccept(new MemberReferenceFixer()); if (configuration.allowAccessModification) { // Fix the access flags of referenced merged classes and their // class members. programClassPool.classesAccept(new AccessFixer()); } // Fix the access flags of the inner classes information. programClassPool.classesAccept( new AllAttributeVisitor(new AllInnerClassesInfoVisitor(new InnerClassesAccessFixer()))); // Tweak the descriptors of duplicate initializers, due to merged // parameter classes. programClassPool.classesAccept( new AllMethodVisitor(new DuplicateInitializerFixer(initializerFixCounter2))); if (initializerFixCounter2.getCount() > 0) { // Fix all invocations of tweaked initializers. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor(new DuplicateInitializerInvocationFixer(addedCounter)))); // Fix all references to tweaked initializers. programClassPool.classesAccept(new MemberReferenceFixer()); } } if (methodInliningUnique) { // Inline methods that are only invoked once. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new MethodInliner( configuration.microEdition, configuration.allowAccessModification, true, methodInliningUniqueCounter)))); } if (methodInliningShort) { // Inline short methods. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new MethodInliner( configuration.microEdition, configuration.allowAccessModification, false, methodInliningShortCounter)))); } if (methodInliningTailrecursion) { // Simplify tail recursion calls. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new TailRecursionSimplifier(methodInliningTailrecursionCounter)))); } if (fieldMarkingPrivate || methodMarkingPrivate) { // Mark all class members that can not be made private. programClassPool.classesAccept(new NonPrivateMemberMarker()); } if (fieldMarkingPrivate) { // Make all non-private fields private, whereever possible. programClassPool.classesAccept( new ClassAccessFilter( 0, ClassConstants.ACC_INTERFACE, new AllFieldVisitor( new MemberAccessFilter( 0, ClassConstants.ACC_PRIVATE, new MemberPrivatizer(fieldMarkingPrivateCounter))))); } if (methodMarkingPrivate) { // Make all non-private methods private, whereever possible. programClassPool.classesAccept( new ClassAccessFilter( 0, ClassConstants.ACC_INTERFACE, new AllMethodVisitor( new MemberAccessFilter( 0, ClassConstants.ACC_PRIVATE, new MemberPrivatizer(methodMarkingPrivateCounter))))); } if ((methodInliningUniqueCounter.getCount() > 0 || methodInliningShortCounter.getCount() > 0 || methodInliningTailrecursionCounter.getCount() > 0) && configuration.allowAccessModification) { // Fix the access flags of referenced classes and class members, // for MethodInliner. programClassPool.classesAccept(new AccessFixer()); } if (methodRemovalParameterCounter.getCount() > 0 || classMergingVerticalCounter.getCount() > 0 || classMergingHorizontalCounter.getCount() > 0 || methodMarkingPrivateCounter.getCount() > 0) { // Fix invocations of interface methods, of methods that have become // non-abstract or private, and of methods that have moved to a // different package. programClassPool.classesAccept( new AllMemberVisitor(new AllAttributeVisitor(new MethodInvocationFixer()))); } if (codeMerging) { // Share common blocks of code at branches. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor(new GotoCommonCodeReplacer(codeMergingCounter)))); } // Create a branch target marker and a code attribute editor that can // be reused for all code attributes. BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); List peepholeOptimizations = new ArrayList(); if (codeSimplificationVariable) { // Peephole optimizations involving local variables. peepholeOptimizations.add( new InstructionSequencesReplacer( InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.VARIABLE, branchTargetFinder, codeAttributeEditor, codeSimplificationVariableCounter)); } if (codeSimplificationArithmetic) { // Peephole optimizations involving arithmetic operations. peepholeOptimizations.add( new InstructionSequencesReplacer( InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.ARITHMETIC, branchTargetFinder, codeAttributeEditor, codeSimplificationArithmeticCounter)); } if (codeSimplificationCast) { // Peephole optimizations involving cast operations. peepholeOptimizations.add( new InstructionSequencesReplacer( InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.CAST, branchTargetFinder, codeAttributeEditor, codeSimplificationCastCounter)); } if (codeSimplificationField) { // Peephole optimizations involving fields. peepholeOptimizations.add( new InstructionSequencesReplacer( InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.FIELD, branchTargetFinder, codeAttributeEditor, codeSimplificationFieldCounter)); } if (codeSimplificationBranch) { // Peephole optimizations involving branches. peepholeOptimizations.add( new InstructionSequencesReplacer( InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.BRANCH, branchTargetFinder, codeAttributeEditor, codeSimplificationBranchCounter)); // Include optimization of branches to branches and returns. peepholeOptimizations.add( new GotoGotoReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); peepholeOptimizations.add( new GotoReturnReplacer(codeAttributeEditor, codeSimplificationBranchCounter)); } if (codeSimplificationString) { // Peephole optimizations involving branches. peepholeOptimizations.add( new InstructionSequencesReplacer( InstructionSequenceConstants.CONSTANTS, InstructionSequenceConstants.STRING, branchTargetFinder, codeAttributeEditor, codeSimplificationStringCounter)); } if (!peepholeOptimizations.isEmpty()) { // Convert the list into an array. InstructionVisitor[] peepholeOptimizationsArray = new InstructionVisitor[peepholeOptimizations.size()]; peepholeOptimizations.toArray(peepholeOptimizationsArray); // Perform the peephole optimisations. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new PeepholeOptimizer( branchTargetFinder, codeAttributeEditor, new MultiInstructionVisitor(peepholeOptimizationsArray))))); } if (codeRemovalException) { // Remove unnecessary exception handlers. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new UnreachableExceptionRemover(codeRemovalExceptionCounter)))); } if (codeRemovalSimple) { // Remove unreachable code. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor(new UnreachableCodeRemover(deletedCounter)))); } if (codeRemovalVariable) { // Remove all unused local variables. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor(new VariableShrinker(codeRemovalVariableCounter)))); } if (codeAllocationVariable) { // Optimize the variables. programClassPool.classesAccept( new AllMethodVisitor( new AllAttributeVisitor( new VariableOptimizer(false, codeAllocationVariableCounter)))); } // Remove unused constants. programClassPool.classesAccept(new ConstantPoolShrinker()); int classMarkingFinalCount = classMarkingFinalCounter.getCount(); int classUnboxingEnumCount = classUnboxingEnumCounter.getCount(); int classMergingVerticalCount = classMergingVerticalCounter.getCount(); int classMergingHorizontalCount = classMergingHorizontalCounter.getCount(); int fieldRemovalWriteonlyCount = fieldRemovalWriteonlyCounter.getCount(); int fieldMarkingPrivateCount = fieldMarkingPrivateCounter.getCount(); int fieldPropagationValueCount = fieldPropagationValueCounter.getCount(); int methodMarkingPrivateCount = methodMarkingPrivateCounter.getCount(); int methodMarkingStaticCount = methodMarkingStaticCounter.getCount(); int methodMarkingFinalCount = methodMarkingFinalCounter.getCount(); int methodRemovalParameterCount = methodRemovalParameterCounter.getCount() - methodMarkingStaticCounter.getCount() - initializerFixCounter1.getCount() - initializerFixCounter2.getCount(); int methodPropagationParameterCount = methodPropagationParameterCounter.getCount(); int methodPropagationReturnvalueCount = methodPropagationReturnvalueCounter.getCount(); int methodInliningShortCount = methodInliningShortCounter.getCount(); int methodInliningUniqueCount = methodInliningUniqueCounter.getCount(); int methodInliningTailrecursionCount = methodInliningTailrecursionCounter.getCount(); int codeMergingCount = codeMergingCounter.getCount(); int codeSimplificationVariableCount = codeSimplificationVariableCounter.getCount(); int codeSimplificationArithmeticCount = codeSimplificationArithmeticCounter.getCount(); int codeSimplificationCastCount = codeSimplificationCastCounter.getCount(); int codeSimplificationFieldCount = codeSimplificationFieldCounter.getCount(); int codeSimplificationBranchCount = codeSimplificationBranchCounter.getCount(); int codeSimplificationStringCount = codeSimplificationStringCounter.getCount(); int codeSimplificationAdvancedCount = codeSimplificationAdvancedCounter.getCount(); int codeRemovalCount = deletedCounter.getCount() - addedCounter.getCount(); int codeRemovalVariableCount = codeRemovalVariableCounter.getCount(); int codeRemovalExceptionCount = codeRemovalExceptionCounter.getCount(); int codeAllocationVariableCount = codeAllocationVariableCounter.getCount(); // Forget about constant fields, parameters, and return values, if they // didn't lead to any useful optimizations. We want to avoid fruitless // additional optimization passes. if (codeSimplificationAdvancedCount == 0) { fieldPropagationValueCount = 0; methodPropagationParameterCount = 0; methodPropagationReturnvalueCount = 0; } if (configuration.verbose) { System.out.println( " Number of finalized classes: " + classMarkingFinalCount + disabled(classMarkingFinal)); System.out.println( " Number of unboxed enum classes: " + classUnboxingEnumCount + disabled(classUnboxingEnum)); System.out.println( " Number of vertically merged classes: " + classMergingVerticalCount + disabled(classMergingVertical)); System.out.println( " Number of horizontally merged classes: " + classMergingHorizontalCount + disabled(classMergingHorizontal)); System.out.println( " Number of removed write-only fields: " + fieldRemovalWriteonlyCount + disabled(fieldRemovalWriteonly)); System.out.println( " Number of privatized fields: " + fieldMarkingPrivateCount + disabled(fieldMarkingPrivate)); System.out.println( " Number of inlined constant fields: " + fieldPropagationValueCount + disabled(fieldPropagationValue)); System.out.println( " Number of privatized methods: " + methodMarkingPrivateCount + disabled(methodMarkingPrivate)); System.out.println( " Number of staticized methods: " + methodMarkingStaticCount + disabled(methodMarkingStatic)); System.out.println( " Number of finalized methods: " + methodMarkingFinalCount + disabled(methodMarkingFinal)); System.out.println( " Number of removed method parameters: " + methodRemovalParameterCount + disabled(methodRemovalParameter)); System.out.println( " Number of inlined constant parameters: " + methodPropagationParameterCount + disabled(methodPropagationParameter)); System.out.println( " Number of inlined constant return values: " + methodPropagationReturnvalueCount + disabled(methodPropagationReturnvalue)); System.out.println( " Number of inlined short method calls: " + methodInliningShortCount + disabled(methodInliningShort)); System.out.println( " Number of inlined unique method calls: " + methodInliningUniqueCount + disabled(methodInliningUnique)); System.out.println( " Number of inlined tail recursion calls: " + methodInliningTailrecursionCount + disabled(methodInliningTailrecursion)); System.out.println( " Number of merged code blocks: " + codeMergingCount + disabled(codeMerging)); System.out.println( " Number of variable peephole optimizations: " + codeSimplificationVariableCount + disabled(codeSimplificationVariable)); System.out.println( " Number of arithmetic peephole optimizations: " + codeSimplificationArithmeticCount + disabled(codeSimplificationArithmetic)); System.out.println( " Number of cast peephole optimizations: " + codeSimplificationCastCount + disabled(codeSimplificationCast)); System.out.println( " Number of field peephole optimizations: " + codeSimplificationFieldCount + disabled(codeSimplificationField)); System.out.println( " Number of branch peephole optimizations: " + codeSimplificationBranchCount + disabled(codeSimplificationBranch)); System.out.println( " Number of string peephole optimizations: " + codeSimplificationStringCount + disabled(codeSimplificationString)); System.out.println( " Number of simplified instructions: " + codeSimplificationAdvancedCount + disabled(codeSimplificationAdvanced)); System.out.println( " Number of removed instructions: " + codeRemovalCount + disabled(codeRemovalAdvanced)); System.out.println( " Number of removed local variables: " + codeRemovalVariableCount + disabled(codeRemovalVariable)); System.out.println( " Number of removed exception blocks: " + codeRemovalExceptionCount + disabled(codeRemovalException)); System.out.println( " Number of optimized local variable frames: " + codeAllocationVariableCount + disabled(codeAllocationVariable)); } return classMarkingFinalCount > 0 || classUnboxingEnumCount > 0 || classMergingVerticalCount > 0 || classMergingHorizontalCount > 0 || fieldRemovalWriteonlyCount > 0 || fieldMarkingPrivateCount > 0 || methodMarkingPrivateCount > 0 || methodMarkingStaticCount > 0 || methodMarkingFinalCount > 0 || fieldPropagationValueCount > 0 || methodRemovalParameterCount > 0 || methodPropagationParameterCount > 0 || methodPropagationReturnvalueCount > 0 || methodInliningShortCount > 0 || methodInliningUniqueCount > 0 || methodInliningTailrecursionCount > 0 || codeMergingCount > 0 || codeSimplificationVariableCount > 0 || codeSimplificationArithmeticCount > 0 || codeSimplificationCastCount > 0 || codeSimplificationFieldCount > 0 || codeSimplificationBranchCount > 0 || codeSimplificationStringCount > 0 || codeSimplificationAdvancedCount > 0 || codeRemovalCount > 0 || codeRemovalVariableCount > 0 || codeRemovalExceptionCount > 0 || codeAllocationVariableCount > 0; }