diff options
author | Brian Carlstrom <bdc@google.com> | 2015-01-08 08:24:06 -0800 |
---|---|---|
committer | Brian Carlstrom <bdc@google.com> | 2015-01-08 10:29:11 -0800 |
commit | cd9e071098d0539dda3a4a5d3f45cfd8814de4ed (patch) | |
tree | 9ac962825d41c4fb8ad1ec0fc2e8b441b42d3869 /src/proguard/optimize/peephole/ClassMerger.java | |
parent | 9961286c06c25cd03464d3e2b00bd9b9dedf96ba (diff) | |
download | proguard-cd9e071098d0539dda3a4a5d3f45cfd8814de4ed.tar.gz |
Upgrade Proguard to 5.1.
Downloaded from:
http://sourceforge.net/projects/proguard/files/proguard/5.1/
Bug: 17550647
(cherry picked from commit 2270795fbe0b277bfd49f40950ecaa78583175cc)
Change-Id: I4d4c6b4f11aca8d5595b7f285c675bc5873d5e24
Diffstat (limited to 'src/proguard/optimize/peephole/ClassMerger.java')
-rw-r--r-- | src/proguard/optimize/peephole/ClassMerger.java | 171 |
1 files changed, 124 insertions, 47 deletions
diff --git a/src/proguard/optimize/peephole/ClassMerger.java b/src/proguard/optimize/peephole/ClassMerger.java index aa40c75..9bcc993 100644 --- a/src/proguard/optimize/peephole/ClassMerger.java +++ b/src/proguard/optimize/peephole/ClassMerger.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2013 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2014 Eric Lafortune (eric@graphics.cornell.edu) * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free @@ -49,9 +49,11 @@ implements ClassVisitor, ConstantVisitor { //* - private static final boolean DEBUG = false; + private static final boolean DEBUG = false; + private static final boolean DETAILS = false; /*/ - private static boolean DEBUG = System.getProperty("cm") != null; + private static boolean DEBUG = System.getProperty("cm") != null; + private static boolean DETAILS = System.getProperty("cmd") != null; //*/ @@ -152,7 +154,9 @@ implements ClassVisitor, // Don't merge annotation classes, with all their introspection and // infinite recursion. - (programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_ANNOTATTION) == 0 && + (programClass.getAccessFlags() & ClassConstants.ACC_ANNOTATTION) == 0 && + + (!DETAILS || print(programClass, "Package visibility?")) && // Only merge classes if we can change the access permissions, or // if they are in the same package, or @@ -161,77 +165,117 @@ implements ClassVisitor, (allowAccessModification || ((programClass.getAccessFlags() & targetClass.getAccessFlags() & - ClassConstants.INTERNAL_ACC_PUBLIC) != 0 && + ClassConstants.ACC_PUBLIC) != 0 && !PackageVisibleMemberContainingClassMarker.containsPackageVisibleMembers(programClass) && !PackageVisibleMemberInvokingClassMarker.invokesPackageVisibleMembers(programClass)) || ClassUtil.internalPackageName(programClass.getName()).equals( ClassUtil.internalPackageName(targetClass.getName()))) && + (!DETAILS || print(programClass, "Interface/abstract/single?")) && + // Only merge two classes or two interfaces or two abstract classes, - // or a class into an interface with a single implementation. + // or a single implementation into its interface. ((programClass.getAccessFlags() & - (ClassConstants.INTERNAL_ACC_INTERFACE | - ClassConstants.INTERNAL_ACC_ABSTRACT)) == + (ClassConstants.ACC_INTERFACE | + ClassConstants.ACC_ABSTRACT)) == (targetClass.getAccessFlags() & - (ClassConstants.INTERNAL_ACC_INTERFACE | - ClassConstants.INTERNAL_ACC_ABSTRACT)) || + (ClassConstants.ACC_INTERFACE | + ClassConstants.ACC_ABSTRACT)) || (isOnlySubClass(programClass, targetClass) && + programClass.getSuperClass() != null && (programClass.getSuperClass().equals(targetClass) || programClass.getSuperClass().equals(targetClass.getSuperClass())))) && + (!DETAILS || print(programClass, "Indirect implementation?")) && + // One class must not implement the other class indirectly. !indirectlyImplementedInterfaces(programClass).contains(targetClass) && !targetClass.extendsOrImplements(programClass) && + (!DETAILS || print(programClass, "Interfaces same subinterfaces?")) && + + // Interfaces must have exactly the same subinterfaces, not + // counting themselves, to avoid any loops in the interface + // hierarchy. + ((programClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 || + (targetClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 || + subInterfaces(programClass, targetClass).equals(subInterfaces(targetClass, programClass))) && + + (!DETAILS || print(programClass, "Same initialized superclasses?")) && + // The two classes must have the same superclasses and interfaces // with static initializers. initializedSuperClasses(programClass).equals(initializedSuperClasses(targetClass)) && + (!DETAILS || print(programClass, "Same instanceofed superclasses?")) && + // The two classes must have the same superclasses and interfaces // that are tested with 'instanceof'. instanceofedSuperClasses(programClass).equals(instanceofedSuperClasses(targetClass)) && + (!DETAILS || print(programClass, "Same caught superclasses?")) && + // The two classes must have the same superclasses that are caught // as exceptions. caughtSuperClasses(programClass).equals(caughtSuperClasses(targetClass)) && + (!DETAILS || print(programClass, "Not .classed?")) && + // The two classes must not both be part of a .class construct. !(DotClassMarker.isDotClassed(programClass) && DotClassMarker.isDotClassed(targetClass)) && + (!DETAILS || print(programClass, "No clashing fields?")) && + // The classes must not have clashing fields. !haveAnyIdenticalFields(programClass, targetClass) && + (!DETAILS || print(programClass, "No unwanted fields?")) && + // The two classes must not introduce any unwanted fields. !introducesUnwantedFields(programClass, targetClass) && !introducesUnwantedFields(targetClass, programClass) && + (!DETAILS || print(programClass, "No shadowed fields?")) && + // The two classes must not shadow each others fields. !shadowsAnyFields(programClass, targetClass) && !shadowsAnyFields(targetClass, programClass) && + (!DETAILS || print(programClass, "No clashing methods?")) && + // The classes must not have clashing methods. !haveAnyIdenticalMethods(programClass, targetClass) && + (!DETAILS || print(programClass, "No abstract methods?")) && + // The classes must not introduce abstract methods, unless // explicitly allowed. (mergeInterfacesAggressively || (!introducesUnwantedAbstractMethods(programClass, targetClass) && !introducesUnwantedAbstractMethods(targetClass, programClass))) && + (!DETAILS || print(programClass, "No overridden methods?")) && + // The classes must not override each others concrete methods. !overridesAnyMethods(programClass, targetClass) && !overridesAnyMethods(targetClass, programClass) && + (!DETAILS || print(programClass, "No shadowed methods?")) && + // The classes must not shadow each others non-private methods. !shadowsAnyMethods(programClass, targetClass) && !shadowsAnyMethods(targetClass, programClass)) { + // We're not actually merging the classes, but only copying the + // contents from the source class to the target class. We'll + // then let all other classes point to it. The shrinking step + // will finally remove the source class. if (DEBUG) { System.out.println("ClassMerger ["+programClass.getName()+"] -> ["+targetClass.getName()+"]"); - System.out.println(" Source interface? ["+((programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]"); - System.out.println(" Target interface? ["+((targetClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE)!=0)+"]"); + System.out.println(" Source interface? ["+((programClass.getAccessFlags() & ClassConstants.ACC_INTERFACE)!=0)+"]"); + System.out.println(" Target interface? ["+((targetClass.getAccessFlags() & ClassConstants.ACC_INTERFACE)!=0)+"]"); System.out.println(" Source subclasses ["+programClass.subClasses+"]"); System.out.println(" Target subclasses ["+targetClass.subClasses+"]"); System.out.println(" Source superclass ["+programClass.getSuperClass().getName()+"]"); @@ -249,17 +293,21 @@ implements ClassVisitor, targetClass.u2accessFlags = ((targetAccessFlags & sourceAccessFlags) & - (ClassConstants.INTERNAL_ACC_INTERFACE | - ClassConstants.INTERNAL_ACC_ABSTRACT)) | + (ClassConstants.ACC_INTERFACE | + ClassConstants.ACC_ABSTRACT)) | ((targetAccessFlags | sourceAccessFlags) & - (ClassConstants.INTERNAL_ACC_PUBLIC | - ClassConstants.INTERNAL_ACC_SUPER | - ClassConstants.INTERNAL_ACC_ANNOTATTION | - ClassConstants.INTERNAL_ACC_ENUM)); - - // Copy over the superclass, unless it's the target class itself. - //if (!targetClass.getName().equals(programClass.getSuperName())) + (ClassConstants.ACC_PUBLIC | + ClassConstants.ACC_SUPER | + ClassConstants.ACC_ANNOTATTION | + ClassConstants.ACC_ENUM)); + + // Copy over the superclass, if it's a non-interface class being + // merged into an interface class. + // However, we're currently never merging in a way that changes the + // superclass. + //if ((programClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) == 0 && + // (targetClass.getAccessFlags() & ClassConstants.ACC_INTERFACE) != 0) //{ // targetClass.u2superClass = // new ConstantAdder(targetClass).addConstant(programClass, programClass.u2superClass); @@ -267,6 +315,9 @@ implements ClassVisitor, // Copy over the interfaces that aren't present yet and that // wouldn't cause loops in the class hierarchy. + // Note that the code shouldn't be iterating over the original + // list at this point. This is why we only add subclasses in + // a separate step. programClass.interfaceConstantsAccept( new ExceptClassConstantFilter(targetClass.getName(), new ImplementedClassConstantFilter(targetClass, @@ -282,10 +333,11 @@ implements ClassVisitor, // Copy over the other attributes. programClass.attributesAccept( - new AttributeNameFilter(new NotMatcher(new OrMatcher(new OrMatcher( - new FixedStringMatcher(ClassConstants.ATTR_SourceFile), - new FixedStringMatcher(ClassConstants.ATTR_InnerClasses)), - new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod))), + new AttributeNameFilter(new NotMatcher( + new OrMatcher(new FixedStringMatcher(ClassConstants.ATTR_BootstrapMethods), + new OrMatcher(new FixedStringMatcher(ClassConstants.ATTR_SourceFile), + new OrMatcher(new FixedStringMatcher(ClassConstants.ATTR_InnerClasses), + new FixedStringMatcher(ClassConstants.ATTR_EnclosingMethod))))), new AttributeAdder(targetClass, true))); // Update the optimization information of the target class. @@ -314,6 +366,14 @@ implements ClassVisitor, } + private boolean print(ProgramClass programClass, String message) + { + System.out.println("Merge ["+targetClass.getName()+"] <- ["+programClass.getName()+"] "+message); + + return true; + } + + // Small utility methods. /** @@ -352,6 +412,23 @@ implements ClassVisitor, /** + * Returns the set of interface subclasses, not including the given class. + */ + private Set subInterfaces(Clazz clazz, Clazz exceptClass) + { + Set set = new HashSet(); + + // Visit all subclasses, collecting the interface classes. + clazz.hierarchyAccept(false, false, false, true, + new ClassAccessFilter(ClassConstants.ACC_INTERFACE, 0, + new ExceptClassesFilter(new Clazz[] { exceptClass }, + new ClassCollector(set)))); + + return set; + } + + + /** * Returns the set of superclasses and interfaces that are initialized. */ private Set initializedSuperClasses(Clazz clazz) @@ -392,7 +469,7 @@ implements ClassVisitor, private Set caughtSuperClasses(Clazz clazz) { // Don't bother if this isn't an exception at all. - if (!clazz.extends_(ClassConstants.INTERNAL_NAME_JAVA_LANG_THROWABLE)) + if (!clazz.extends_(ClassConstants.NAME_JAVA_LANG_THROWABLE)) { return Collections.EMPTY_SET; } @@ -410,8 +487,8 @@ implements ClassVisitor, /** - * Returns whether the two given classes have class members with the same - * name and descriptor. + * Returns whether the two given classes have fields with the same + * names and descriptors. */ private boolean haveAnyIdenticalFields(Clazz clazz, Clazz targetClass) { @@ -445,7 +522,7 @@ implements ClassVisitor, MemberCounter counter = new MemberCounter(); // Count all non-static fields in the the source class. - programClass.fieldsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_STATIC, + programClass.fieldsAccept(new MemberAccessFilter(0, ClassConstants.ACC_STATIC, counter)); return counter.getCount() > 0; @@ -465,7 +542,7 @@ implements ClassVisitor, clazz.hierarchyAccept(true, false, false, true, new AllFieldVisitor( new SimilarMemberVisitor(targetClass, true, true, true, false, - new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, + new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE, counter)))); return counter.getCount() > 0; @@ -482,9 +559,9 @@ implements ClassVisitor, // Visit all non-abstract methods, counting the ones that are also // present in the target class. - clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT, + clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.ACC_ABSTRACT, new SimilarMemberVisitor(targetClass, true, false, false, false, - new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_ABSTRACT, + new MemberAccessFilter(0, ClassConstants.ACC_ABSTRACT, counter)))); return counter.getCount() > 0; @@ -501,8 +578,8 @@ implements ClassVisitor, // It's ok if the target class is already abstract and it has at most // the class as a subclass. if ((targetClass.getAccessFlags() & - (ClassConstants.INTERNAL_ACC_ABSTRACT | - ClassConstants.INTERNAL_ACC_INTERFACE)) != 0 && + (ClassConstants.ACC_ABSTRACT | + ClassConstants.ACC_INTERFACE)) != 0 && (targetClass.subClasses == null || isOnlySubClass(clazz, targetClass))) { @@ -514,12 +591,12 @@ implements ClassVisitor, // Collect all abstract methods, and similar abstract methods in the // class hierarchy of the target class. - clazz.methodsAccept(new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0, + clazz.methodsAccept(new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0, new MultiMemberVisitor(new MemberVisitor[] { counter, new SimilarMemberVisitor(targetClass, true, true, true, false, - new MemberAccessFilter(ClassConstants.INTERNAL_ACC_ABSTRACT, 0, + new MemberAccessFilter(ClassConstants.ACC_ABSTRACT, 0, new MemberCollector(targetSet))) }))); @@ -537,11 +614,11 @@ implements ClassVisitor, // Visit all non-private non-static methods, counting the ones that are // being overridden in the class hierarchy of the target class. - clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT, - new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)), - new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)), + clazz.methodsAccept(new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC | ClassConstants.ACC_ABSTRACT, + new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_CLINIT)), + new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_INIT)), new SimilarMemberVisitor(targetClass, true, true, false, false, - new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT, + new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE | ClassConstants.ACC_STATIC | ClassConstants.ACC_ABSTRACT, counter)))))); return counter.getCount() > 0; @@ -560,20 +637,20 @@ implements ClassVisitor, // non-private methods in the class hierarchy of the target class. clazz.hierarchyAccept(true, false, false, true, new AllMethodVisitor( - new MemberAccessFilter(ClassConstants.INTERNAL_ACC_PRIVATE, 0, - new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_INIT)), + new MemberAccessFilter(ClassConstants.ACC_PRIVATE, 0, + new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_INIT)), new SimilarMemberVisitor(targetClass, true, true, true, false, - new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, + new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE, counter)))))); // Visit all static methods, counting the ones that are shadowing // non-private methods in the class hierarchy of the target class. clazz.hierarchyAccept(true, false, false, true, new AllMethodVisitor( - new MemberAccessFilter(ClassConstants.INTERNAL_ACC_STATIC, 0, - new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.INTERNAL_METHOD_NAME_CLINIT)), + new MemberAccessFilter(ClassConstants.ACC_STATIC, 0, + new MemberNameFilter(new NotMatcher(new FixedStringMatcher(ClassConstants.METHOD_NAME_CLINIT)), new SimilarMemberVisitor(targetClass, true, true, true, false, - new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, + new MemberAccessFilter(0, ClassConstants.ACC_PRIVATE, counter)))))); return counter.getCount() > 0; @@ -638,4 +715,4 @@ implements ClassVisitor, // Linked methods share their optimization info. } } -}
\ No newline at end of file +} |