diff options
Diffstat (limited to 'src/proguard/shrink')
-rw-r--r-- | src/proguard/shrink/AnnotationUsageMarker.java | 76 | ||||
-rw-r--r-- | src/proguard/shrink/ClassShrinker.java | 73 | ||||
-rw-r--r-- | src/proguard/shrink/InnerUsageMarker.java | 2 | ||||
-rw-r--r-- | src/proguard/shrink/InterfaceUsageMarker.java | 2 | ||||
-rw-r--r-- | src/proguard/shrink/LocalVariableTypeUsageMarker.java | 178 | ||||
-rw-r--r-- | src/proguard/shrink/ShortestUsageMark.java | 2 | ||||
-rw-r--r-- | src/proguard/shrink/ShortestUsageMarker.java | 2 | ||||
-rw-r--r-- | src/proguard/shrink/ShortestUsagePrinter.java | 56 | ||||
-rw-r--r-- | src/proguard/shrink/Shrinker.java | 43 | ||||
-rw-r--r-- | src/proguard/shrink/SignatureUsageMarker.java | 117 | ||||
-rw-r--r-- | src/proguard/shrink/UsageMarker.java | 250 | ||||
-rw-r--r-- | src/proguard/shrink/UsagePrinter.java | 46 | ||||
-rw-r--r-- | src/proguard/shrink/UsedClassFilter.java | 2 | ||||
-rw-r--r-- | src/proguard/shrink/UsedMemberFilter.java | 4 |
14 files changed, 653 insertions, 200 deletions
diff --git a/src/proguard/shrink/AnnotationUsageMarker.java b/src/proguard/shrink/AnnotationUsageMarker.java index 9aaae34..b9051a0 100644 --- a/src/proguard/shrink/AnnotationUsageMarker.java +++ b/src/proguard/shrink/AnnotationUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 @@ -52,8 +52,7 @@ implements AttributeVisitor, // Fields acting as a return parameters for several methods. private boolean attributeUsed; private boolean annotationUsed; - private boolean elementValueUsed; - private boolean classUsed; + private boolean allClassesUsed; private boolean methodUsed; @@ -151,9 +150,6 @@ implements AttributeVisitor, markConstant(clazz, constantElementValue.u2elementNameIndex); markConstant(clazz, constantElementValue.u2constantValueIndex); - - // The return value. - elementValueUsed = true; } } @@ -163,10 +159,10 @@ implements AttributeVisitor, if (isReferencedMethodUsed(enumConstantElementValue)) { // Check the referenced classes. - classUsed = true; - enumConstantElementValue.referencedClassesAccept(usageMarker); + allClassesUsed = true; + enumConstantElementValue.referencedClassesAccept(this); - if (classUsed) + if (allClassesUsed) { // Mark the element value as being used. usageMarker.markAsUsed(enumConstantElementValue); @@ -174,9 +170,6 @@ implements AttributeVisitor, markConstant(clazz, enumConstantElementValue.u2elementNameIndex); markConstant(clazz, enumConstantElementValue.u2typeNameIndex); markConstant(clazz, enumConstantElementValue.u2constantNameIndex); - - // The return value. - elementValueUsed = true; } } } @@ -186,21 +179,16 @@ implements AttributeVisitor, { if (isReferencedMethodUsed(classElementValue)) { - // Check the referenced classes. - classUsed = true; - classElementValue.referencedClassesAccept(usageMarker); - - if (classUsed) - { - // Mark the element value as being used. - usageMarker.markAsUsed(classElementValue); + // Mark the element value as being used. + usageMarker.markAsUsed(classElementValue); - markConstant(clazz, classElementValue.u2elementNameIndex); - markConstant(clazz, classElementValue.u2classInfoIndex); + markConstant(clazz, classElementValue.u2elementNameIndex); + markConstant(clazz, classElementValue.u2classInfoIndex); - // The return value. - elementValueUsed = true; - } + // Mark the referenced classes, since they can be retrieved from + // the annotation and then used. + // TODO: This could mark more annotation methods, affecting other annotations. + classElementValue.referencedClassesAccept(usageMarker); } } @@ -221,9 +209,6 @@ implements AttributeVisitor, usageMarker.markAsUsed(annotationElementValue); markConstant(clazz, annotationElementValue.u2elementNameIndex); - - // The return value. - elementValueUsed = true; } annotationUsed = oldAnnotationUsed; @@ -235,26 +220,13 @@ implements AttributeVisitor, { if (isReferencedMethodUsed(arrayElementValue)) { - boolean oldelementValueUsed = elementValueUsed; - // Check and mark the contained element values. - elementValueUsed = false; arrayElementValue.elementValuesAccept(clazz, annotation, this); - if (elementValueUsed) - { - // Mark the element value as being used. - usageMarker.markAsUsed(arrayElementValue); - - markConstant(clazz, arrayElementValue.u2elementNameIndex); + // Mark the element value as being used. + usageMarker.markAsUsed(arrayElementValue); - // The return value. - //elementValueUsed = true; - } - else - { - elementValueUsed = oldelementValueUsed; - } + markConstant(clazz, arrayElementValue.u2elementNameIndex); } } @@ -269,17 +241,15 @@ implements AttributeVisitor, public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { - classUsed = usageMarker.isUsed(classConstant); - // Is the class constant marked as being used? - if (!classUsed) + if (!usageMarker.isUsed(classConstant)) { // Check the referenced class. - classUsed = true; + allClassesUsed = true; classConstant.referencedClassAccept(this); // Is the referenced class marked as being used? - if (classUsed) + if (allClassesUsed) { // Mark the class constant and its Utf8 constant. usageMarker.markAsUsed(classConstant); @@ -294,13 +264,12 @@ implements AttributeVisitor, public void visitProgramClass(ProgramClass programClass) { - classUsed = usageMarker.isUsed(programClass); + allClassesUsed &= usageMarker.isUsed(programClass); } public void visitLibraryClass(LibraryClass libraryClass) { - classUsed = true; } @@ -314,7 +283,6 @@ implements AttributeVisitor, public void visitLibraryMethod(LibraryClass LibraryClass, LibraryMethod libraryMethod) { - classUsed = true; } @@ -326,10 +294,10 @@ implements AttributeVisitor, private boolean isReferencedClassUsed(Annotation annotation) { // Check if the referenced class is being used. - classUsed = true; + allClassesUsed = true; annotation.referencedClassAccept(this); - return classUsed; + return allClassesUsed; } diff --git a/src/proguard/shrink/ClassShrinker.java b/src/proguard/shrink/ClassShrinker.java index 0b5c5b7..f590c63 100644 --- a/src/proguard/shrink/ClassShrinker.java +++ b/src/proguard/shrink/ClassShrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 @@ -24,15 +24,17 @@ import proguard.classfile.*; import proguard.classfile.attribute.*; import proguard.classfile.attribute.annotation.*; import proguard.classfile.attribute.annotation.visitor.*; -import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; import proguard.classfile.editor.*; import proguard.classfile.util.*; import proguard.classfile.visitor.*; +import java.util.Arrays; + /** - * This ClassVisitor removes constant pool entries and class members that - * are not marked as being used. + * This ClassVisitor removes constant pool entries, class members, and other + * class elements that are not marked as being used. * * @see UsageMarker * @@ -48,8 +50,7 @@ implements ClassVisitor, { private final UsageMarker usageMarker; - private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; - + private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); @@ -76,7 +77,7 @@ implements ClassVisitor, programClass.u2interfacesCount); // Shrinking the constant pool also sets up an index map. - programClass.u2constantPoolCount = + int newConstantPoolCount = shrinkConstantPool(programClass.constantPool, programClass.u2constantPoolCount); @@ -98,9 +99,15 @@ implements ClassVisitor, programClass.methodsAccept(this); programClass.attributesAccept(this); - // Remap all constant pool references. - constantPoolRemapper.setConstantIndexMap(constantIndexMap); - constantPoolRemapper.visitProgramClass(programClass); + // Remap the references to the constant pool if it has shrunk. + if (newConstantPoolCount < programClass.u2constantPoolCount) + { + programClass.u2constantPoolCount = newConstantPoolCount; + + // Remap all constant pool references. + constantPoolRemapper.setConstantIndexMap(constantIndexMap); + constantPoolRemapper.visitProgramClass(programClass); + } // Remove the unused interfaces from the class signature. programClass.attributesAccept(new SignatureShrinker()); @@ -140,6 +147,15 @@ implements ClassVisitor, public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + // Shrink the array of BootstrapMethodInfo objects. + bootstrapMethodsAttribute.u2bootstrapMethodsCount = + shrinkArray(bootstrapMethodsAttribute.bootstrapMethods, + bootstrapMethodsAttribute.u2bootstrapMethodsCount); + } + + public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) { // Shrink the array of InnerClassesInfo objects. @@ -173,6 +189,27 @@ implements ClassVisitor, codeAttribute.u2attributesCount = shrinkArray(codeAttribute.attributes, codeAttribute.u2attributesCount); + + // Shrink the attributes themselves. + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) + { + // Shrink the local variable info array. + localVariableTableAttribute.u2localVariableTableLength = + shrinkArray(localVariableTableAttribute.localVariableTable, + localVariableTableAttribute.u2localVariableTableLength); + } + + + public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) + { + // Shrink the local variable type info array. + localVariableTypeTableAttribute.u2localVariableTypeTableLength = + shrinkArray(localVariableTypeTableAttribute.localVariableTypeTable, + localVariableTypeTableAttribute.u2localVariableTypeTableLength); } @@ -349,10 +386,7 @@ implements ClassVisitor, } // Clear the remaining constant pool elements. - for (int index = counter; index < length; index++) - { - constantPool[index] = null; - } + Arrays.fill(constantPool, counter, length, null); return counter; } @@ -377,10 +411,7 @@ implements ClassVisitor, } // Clear the remaining array elements. - for (int index = counter; index < length; index++) - { - array[index] = 0; - } + Arrays.fill(array, counter, length, 0); return counter; } @@ -437,10 +468,10 @@ implements ClassVisitor, } } - // Clear the remaining array elements. - for (int index = counter; index < length; index++) + // Clear any remaining array elements. + if (counter < length) { - array[index] = null; + Arrays.fill(array, counter, length, null); } return counter; diff --git a/src/proguard/shrink/InnerUsageMarker.java b/src/proguard/shrink/InnerUsageMarker.java index b8ca801..6d77e81 100644 --- a/src/proguard/shrink/InnerUsageMarker.java +++ b/src/proguard/shrink/InnerUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 diff --git a/src/proguard/shrink/InterfaceUsageMarker.java b/src/proguard/shrink/InterfaceUsageMarker.java index 7599898..240838e 100644 --- a/src/proguard/shrink/InterfaceUsageMarker.java +++ b/src/proguard/shrink/InterfaceUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 diff --git a/src/proguard/shrink/LocalVariableTypeUsageMarker.java b/src/proguard/shrink/LocalVariableTypeUsageMarker.java new file mode 100644 index 0000000..573d8f6 --- /dev/null +++ b/src/proguard/shrink/LocalVariableTypeUsageMarker.java @@ -0,0 +1,178 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2013 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package proguard.shrink; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.*; +import proguard.classfile.constant.Constant; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This AttributeVisitor recursively marks all information that points to used + * classes, in the LocalVariableTable and LocalVariableTypeTable attributes that + * it visits. + * + * @see UsageMarker + * + * @author Eric Lafortune + */ +public class LocalVariableTypeUsageMarker +extends SimplifiedVisitor +implements AttributeVisitor, + LocalVariableInfoVisitor, + LocalVariableTypeInfoVisitor, + ClassVisitor, + ConstantVisitor +{ + private final UsageMarker usageMarker; + + // Fields acting as a return parameters for several methods. + private boolean tableUsed; + private boolean variableInfoUsed; + + + /** + * Creates a new LocalVariableTypeUsageMarker. + * @param usageMarker the usage marker that is used to mark the classes + * and class members. + */ + public LocalVariableTypeUsageMarker(UsageMarker usageMarker) + { + this.usageMarker = usageMarker; + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) + { + // Check and mark the individual entries. + tableUsed = false; + localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + + // Mark the table if any of the entries is marked. + if (tableUsed) + { + usageMarker.markAsUsed(localVariableTableAttribute); + + markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); + } + } + + + public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) + { + // Check and mark the individual entries. + tableUsed = false; + localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + + // Mark the table if any of the entries is marked. + if (tableUsed) + { + usageMarker.markAsUsed(localVariableTypeTableAttribute); + + markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); + } + } + + + // Implementations for LocalVariableInfoVisitor. + + public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) + { + // Only keep the local variable info if all of its classes are used. + variableInfoUsed = true; + localVariableInfo.referencedClassAccept(this); + + if (variableInfoUsed) + { + // We got a positive used flag, so the local variable info is useful. + usageMarker.markAsUsed(localVariableInfo); + + markConstant(clazz, localVariableInfo.u2nameIndex); + markConstant(clazz, localVariableInfo.u2descriptorIndex); + + tableUsed = true; + } + } + + + // Implementations for LocalVariableTypeInfoVisitor. + + public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) + { + // Only keep the local variable info if all of its classes are used. + variableInfoUsed = true; + localVariableTypeInfo.referencedClassesAccept(this); + + if (variableInfoUsed) + { + // We got a positive used flag, so the local variable info is useful. + usageMarker.markAsUsed(localVariableTypeInfo); + + markConstant(clazz, localVariableTypeInfo.u2nameIndex); + markConstant(clazz, localVariableTypeInfo.u2signatureIndex); + + tableUsed = true; + } + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + + public void visitProgramClass(ProgramClass programClass) + { + // Don't keep the local variable info if one of its classes is not used. + if (!usageMarker.isUsed(programClass)) + { + variableInfoUsed = false; + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) + { + usageMarker.markAsUsed(constant); + } + + + // Small utility methods. + + /** + * Marks the given constant pool entry of the given class. + */ + private void markConstant(Clazz clazz, int index) + { + clazz.constantPoolEntryAccept(index, this); + } +} diff --git a/src/proguard/shrink/ShortestUsageMark.java b/src/proguard/shrink/ShortestUsageMark.java index 757c713..e2df7fa 100644 --- a/src/proguard/shrink/ShortestUsageMark.java +++ b/src/proguard/shrink/ShortestUsageMark.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 diff --git a/src/proguard/shrink/ShortestUsageMarker.java b/src/proguard/shrink/ShortestUsageMarker.java index da8fad3..1ac6e7e 100644 --- a/src/proguard/shrink/ShortestUsageMarker.java +++ b/src/proguard/shrink/ShortestUsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 diff --git a/src/proguard/shrink/ShortestUsagePrinter.java b/src/proguard/shrink/ShortestUsagePrinter.java index db42fe1..8740b9f 100644 --- a/src/proguard/shrink/ShortestUsagePrinter.java +++ b/src/proguard/shrink/ShortestUsagePrinter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 @@ -21,7 +21,9 @@ package proguard.shrink; import proguard.classfile.*; -import proguard.classfile.util.ClassUtil; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.util.*; import proguard.classfile.visitor.*; import java.io.PrintStream; @@ -36,8 +38,10 @@ import java.io.PrintStream; * @author Eric Lafortune */ public class ShortestUsagePrinter +extends SimplifiedVisitor implements ClassVisitor, - MemberVisitor + MemberVisitor, + AttributeVisitor { private final ShortestUsageMarker shortestUsageMarker; private final boolean verbose; @@ -117,8 +121,7 @@ implements ClassVisitor, ps.println(ClassUtil.externalClassName(programClass.getName()) + (verbose ? ": " + ClassUtil.externalFullFieldDescription(0, name, type): - "." + name) + - lineNumberRange(programClass, programField)); + "." + name)); // Print the reason for keeping this method. printReason(programField); @@ -131,11 +134,12 @@ implements ClassVisitor, String name = programMethod.getName(programClass); String type = programMethod.getDescriptor(programClass); - ps.println(ClassUtil.externalClassName(programClass.getName()) + - (verbose ? - ": " + ClassUtil.externalFullMethodDescription(programClass.getName(), 0, name, type): - "." + name) + - lineNumberRange(programClass, programMethod)); + ps.print(ClassUtil.externalClassName(programClass.getName()) + + (verbose ? + ": " + ClassUtil.externalFullMethodDescription(programClass.getName(), 0, name, type): + "." + name)); + programMethod.attributesAccept(programClass, this); + ps.println(); // Print the reason for keeping this method. printReason(programMethod); @@ -174,6 +178,25 @@ implements ClassVisitor, } + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) + { + ps.print(" (" + + lineNumberTableAttribute.getLowestLineNumber() + ":" + + lineNumberTableAttribute.getHighestLineNumber() + ")"); + } + + // Small utility methods. private void printReason(VisitorAccepter visitorAccepter) @@ -194,17 +217,4 @@ implements ClassVisitor, ps.println(" is not being kept.\n"); } } - - - /** - * Returns the line number range of the given class member, followed by a - * colon, or just an empty String if no range is available. - */ - private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) - { - String range = programMember.getLineNumberRange(programClass); - return range != null ? - (" (" + range + ")") : - ""; - } } diff --git a/src/proguard/shrink/Shrinker.java b/src/proguard/shrink/Shrinker.java index edbc27f..0472c3d 100644 --- a/src/proguard/shrink/Shrinker.java +++ b/src/proguard/shrink/Shrinker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 @@ -21,7 +21,7 @@ package proguard.shrink; import proguard.*; -import proguard.classfile.ClassPool; +import proguard.classfile.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.visitor.*; @@ -67,9 +67,20 @@ public class Shrinker new UsageMarker() : new ShortestUsageMarker(); + // Automatically mark the parameterless constructors of seed classes, + // mainly for convenience and for backward compatibility. + ClassVisitor classUsageMarker = + new MultiClassVisitor(new ClassVisitor[] + { + usageMarker, + new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, + ClassConstants.INTERNAL_METHOD_TYPE_INIT, + usageMarker) + }); + ClassPoolVisitor classPoolvisitor = ClassSpecificationVisitorFactory.createClassPoolVisitor(configuration.keep, - usageMarker, + classUsageMarker, usageMarker, true, false, @@ -89,6 +100,8 @@ public class Shrinker { new InnerUsageMarker(usageMarker), new AnnotationUsageMarker(usageMarker), + new SignatureUsageMarker(usageMarker), + new LocalVariableTypeUsageMarker(usageMarker) })))); // Should we explain ourselves? @@ -113,15 +126,21 @@ public class Shrinker if (configuration.printUsage != null) { - PrintStream ps = isFile(configuration.printUsage) ? - new PrintStream(new BufferedOutputStream(new FileOutputStream(configuration.printUsage))) : - System.out; + PrintStream ps = + configuration.printUsage == Configuration.STD_OUT ? System.out : + new PrintStream( + new BufferedOutputStream( + new FileOutputStream(configuration.printUsage))); // Print out items that will be removed. programClassPool.classesAcceptAlphabetically( new UsagePrinter(usageMarker, true, ps)); - if (ps != System.out) + if (ps == System.out) + { + ps.flush(); + } + else { ps.close(); } @@ -157,14 +176,4 @@ public class Shrinker return newProgramClassPool; } - - - /** - * Returns whether the given file is actually a file, or just a placeholder - * for the standard output. - */ - private boolean isFile(File file) - { - return file.getPath().length() > 0; - } } diff --git a/src/proguard/shrink/SignatureUsageMarker.java b/src/proguard/shrink/SignatureUsageMarker.java new file mode 100644 index 0000000..9c5cd4d --- /dev/null +++ b/src/proguard/shrink/SignatureUsageMarker.java @@ -0,0 +1,117 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2013 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +package proguard.shrink; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.*; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.ClassVisitor; + +/** + * This AttributeVisitor recursively marks all Signature attributes that it + * visits and that point to used classes. + * + * @see UsageMarker + * + * @author Eric Lafortune + */ +public class SignatureUsageMarker +extends SimplifiedVisitor +implements AttributeVisitor, + ClassVisitor, + ConstantVisitor +{ + private final UsageMarker usageMarker; + + // Fields acting as a return parameters for several methods. + private boolean attributeUsed; + + + /** + * Creates a new SignatureUsageMarker. + * @param usageMarker the usage marker that is used to mark the classes + * and class members. + */ + public SignatureUsageMarker(UsageMarker usageMarker) + { + this.usageMarker = usageMarker; + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) + { + // Only keep the signature if all of its classes are used. + attributeUsed = true; + signatureAttribute.referencedClassesAccept(this); + + if (attributeUsed) + { + // We got a positive used flag, so the signature is useful. + usageMarker.markAsUsed(signatureAttribute); + + markConstant(clazz, signatureAttribute.u2attributeNameIndex); + markConstant(clazz, signatureAttribute.u2signatureIndex); + } + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + + public void visitProgramClass(ProgramClass programClass) + { + // Don't keep the signature if one of its classes is not used. + if (!usageMarker.isUsed(programClass)) + { + attributeUsed = false; + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) + { + usageMarker.markAsUsed(constant); + } + + + // Small utility methods. + + /** + * Marks the given constant pool entry of the given class. + */ + private void markConstant(Clazz clazz, int index) + { + clazz.constantPoolEntryAccept(index, this); + } +} diff --git a/src/proguard/shrink/UsageMarker.java b/src/proguard/shrink/UsageMarker.java index e913046..51210b5 100644 --- a/src/proguard/shrink/UsageMarker.java +++ b/src/proguard/shrink/UsageMarker.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 @@ -27,10 +27,10 @@ import proguard.classfile.attribute.preverification.*; import proguard.classfile.attribute.preverification.visitor.*; import proguard.classfile.attribute.visitor.*; import proguard.classfile.constant.*; -import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.constant.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; -import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.util.*; import proguard.classfile.visitor.*; @@ -65,18 +65,15 @@ implements ClassVisitor, private static final Object USED = new Object(); - private final MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker(); - private final MyPossiblyUsedMemberUsageMarker possiblyUsedMemberUsageMarker = new MyPossiblyUsedMemberUsageMarker(); -// private ClassVisitor dynamicClassMarker = -// new MultiClassVisitor( -// new ClassVisitor[] -// { -// this, -// new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, -// ClassConstants.INTERNAL_METHOD_TYPE_INIT, -// this) -// }); - + private final MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker(); + private final MyPossiblyUsedMemberUsageMarker possiblyUsedMemberUsageMarker = new MyPossiblyUsedMemberUsageMarker(); + private final MemberVisitor nonEmptyMethodUsageMarker = new AllAttributeVisitor( + new MyNonEmptyMethodUsageMarker()); + private final ConstantVisitor parameterlessConstructorMarker = new ConstantTagFilter(new int[] { ClassConstants.CONSTANT_String, ClassConstants.CONSTANT_Class }, + new ReferencedClassVisitor( + new NamedMethodVisitor(ClassConstants.INTERNAL_METHOD_NAME_INIT, + ClassConstants.INTERNAL_METHOD_TYPE_INIT, + this))); // Implementations for ClassVisitor. @@ -107,15 +104,10 @@ implements ClassVisitor, programClass.hierarchyAccept(false, false, true, false, interfaceUsageMarker); - // Explicitly mark the <clinit> method. + // Explicitly mark the <clinit> method, if it's not empty. programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT, ClassConstants.INTERNAL_METHOD_TYPE_CLINIT, - this); - - // Explicitly mark the parameterless <init> method. - programClass.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT, - ClassConstants.INTERNAL_METHOD_TYPE_INIT, - this); + nonEmptyMethodUsageMarker); // Process all class members that have already been marked as possibly used. programClass.fieldsAccept(possiblyUsedMemberUsageMarker); @@ -187,6 +179,10 @@ implements ClassVisitor, } + /** + * This MemberVisitor marks ProgramField and ProgramMethod objects that + * have already been marked as possibly used. + */ private class MyPossiblyUsedMemberUsageMarker extends SimplifiedVisitor implements MemberVisitor @@ -230,6 +226,28 @@ implements ClassVisitor, } + /** + * This AttributeVisitor marks ProgramMethod objects of non-empty methods. + */ + private class MyNonEmptyMethodUsageMarker + extends SimplifiedVisitor + implements AttributeVisitor + { + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + if (codeAttribute.u4codeLength > 1) + { + method.accept(clazz, UsageMarker.this); + } + } + } + + // Implementations for MemberVisitor. public void visitProgramField(ProgramClass programClass, ProgramField programField) @@ -335,15 +353,26 @@ implements ClassVisitor, */ protected void markMethodHierarchy(Clazz clazz, Method method) { - if ((method.getAccessFlags() & + int accessFlags = method.getAccessFlags(); + if ((accessFlags & (ClassConstants.INTERNAL_ACC_PRIVATE | - ClassConstants.INTERNAL_ACC_STATIC)) == 0) + ClassConstants.INTERNAL_ACC_STATIC)) == 0 && + !ClassUtil.isInitializer(method.getName(clazz))) { + // We can skip private and static methods in the hierarchy, and + // also abstract methods, unless they might widen a current + // non-public access. + int requiredUnsetAccessFlags = + ClassConstants.INTERNAL_ACC_PRIVATE | + ClassConstants.INTERNAL_ACC_STATIC | + ((accessFlags & ClassConstants.INTERNAL_ACC_PUBLIC) == 0 ? 0 : + ClassConstants.INTERNAL_ACC_ABSTRACT); + clazz.accept(new ConcreteClassDownTraveler( new ClassHierarchyTraveler(true, true, false, true, new NamedMethodVisitor(method.getName(clazz), method.getDescriptor(clazz), - new MemberAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE | ClassConstants.INTERNAL_ACC_STATIC | ClassConstants.INTERNAL_ACC_ABSTRACT, + new MemberAccessFilter(0, requiredUnsetAccessFlags, this))))); } } @@ -395,11 +424,7 @@ implements ClassVisitor, markConstant(clazz, stringConstant.u2stringIndex); - // Mark the referenced class and its parameterless constructor, - // if the string is being used in a Class.forName construct. - //stringConstant.referencedClassAccept(dynamicClassMarker); - - // Mark the referenced class or class member, if any. + // Mark the referenced class and class member, if any. stringConstant.referencedClassAccept(this); stringConstant.referencedMemberAccept(this); } @@ -415,6 +440,31 @@ implements ClassVisitor, } + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + if (shouldBeMarkedAsUsed(invokeDynamicConstant)) + { + markAsUsed(invokeDynamicConstant); + + markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); + + // Mark the bootstrap methods attribute. + clazz.attributesAccept(new MyBootStrapMethodUsageMarker(invokeDynamicConstant.u2bootstrapMethodAttributeIndex)); + } + } + + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + if (shouldBeMarkedAsUsed(methodHandleConstant)) + { + markAsUsed(methodHandleConstant); + + markConstant(clazz, methodHandleConstant.u2referenceIndex); + } + } + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { if (shouldBeMarkedAsUsed(refConstant)) @@ -450,6 +500,17 @@ implements ClassVisitor, } + public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) + { + if (shouldBeMarkedAsUsed(methodTypeConstant)) + { + markAsUsed(methodTypeConstant); + + markConstant(clazz, methodTypeConstant.u2descriptorIndex); + } + } + + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { if (shouldBeMarkedAsUsed(nameAndTypeConstant)) @@ -462,6 +523,58 @@ implements ClassVisitor, } + /** + * This AttributeVisitor marks the bootstrap methods attributes, their + * method entries, their method handles, and their arguments. + */ + private class MyBootStrapMethodUsageMarker + extends SimplifiedVisitor + implements AttributeVisitor, + BootstrapMethodInfoVisitor + { + private int bootstrapMethodIndex; + + + private MyBootStrapMethodUsageMarker(int bootstrapMethodIndex) + { + this.bootstrapMethodIndex = bootstrapMethodIndex; + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + if (shouldBeMarkedAsUsed(bootstrapMethodsAttribute)) + { + markAsUsed(bootstrapMethodsAttribute); + + markConstant(clazz, bootstrapMethodsAttribute.u2attributeNameIndex); + + bootstrapMethodsAttribute.bootstrapMethodEntryAccept(clazz, + bootstrapMethodIndex, + this); + } + } + + + // Implementations for BootstrapMethodInfoVisitor. + + public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) + { + markAsUsed(bootstrapMethodInfo); + + markConstant(clazz, bootstrapMethodInfo.u2methodHandleIndex); + + // Mark the constant pool entries referenced by the arguments. + bootstrapMethodInfo.methodArgumentsAccept(clazz, UsageMarker.this); + } + } + + // Implementations for AttributeVisitor. // Note that attributes are typically only referenced once, so we don't // test if they have been marked already. @@ -475,6 +588,13 @@ implements ClassVisitor, } + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + // Don't mark the attribute and its name here. We may mark it in + // MyBootStrapMethodsAttributeUsageMarker. + } + + public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { markAsUsed(sourceFileAttribute); @@ -538,10 +658,12 @@ implements ClassVisitor, public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) { - markAsUsed(signatureAttribute); - - markConstant(clazz, signatureAttribute.u2attributeNameIndex); - markConstant(clazz, signatureAttribute.u2signatureIndex); + // Don't mark the attribute and its contents yet. We may mark them later, + // in SignatureUsageMarker. + //markAsUsed(signatureAttribute); + // + //markConstant(clazz, signatureAttribute.u2attributeNameIndex); + //markConstant(clazz, signatureAttribute.u2signatureIndex); } @@ -611,23 +733,27 @@ implements ClassVisitor, public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) { - markAsUsed(localVariableTableAttribute); - - markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); - - // Mark the constant pool entries referenced by the local variables. - localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + // Don't mark the attribute and its contents yet. We may mark them later, + // in LocalVariableTypeUsageMarker. + //markAsUsed(localVariableTableAttribute); + // + //markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); + // + //// Mark the constant pool entries referenced by the local variables. + //localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) { - markAsUsed(localVariableTypeTableAttribute); - - markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); - - // Mark the constant pool entries referenced by the local variable types. - localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + // Don't mark the attribute and its contents yet. We may mark them later, + // in LocalVariableTypeUsageMarker. + //markAsUsed(localVariableTypeTableAttribute); + // + //markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); + // + //// Mark the constant pool entries referenced by the local variable types. + //localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); } @@ -635,12 +761,12 @@ implements ClassVisitor, { // Don't mark the attribute and its contents yet. We may mark them later, // in AnnotationUsageMarker. -// markAsUsed(annotationsAttribute); -// -// markConstant(clazz, annotationsAttribute.u2attributeNameIndex); -// -// // Mark the constant pool entries referenced by the annotations. -// annotationsAttribute.annotationsAccept(clazz, this); + //markAsUsed(annotationsAttribute); + // + //markConstant(clazz, annotationsAttribute.u2attributeNameIndex); + // + //// Mark the constant pool entries referenced by the annotations. + //annotationsAttribute.annotationsAccept(clazz, this); } @@ -648,12 +774,12 @@ implements ClassVisitor, { // Don't mark the attribute and its contents yet. We may mark them later, // in AnnotationUsageMarker. -// markAsUsed(parameterAnnotationsAttribute); -// -// markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); -// -// // Mark the constant pool entries referenced by the annotations. -// parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); + //markAsUsed(parameterAnnotationsAttribute); + // + //markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); + // + //// Mark the constant pool entries referenced by the annotations. + //parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); } @@ -837,6 +963,12 @@ implements ClassVisitor, public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) { markConstant(clazz, constantInstruction.constantIndex); + + // Also mark the parameterless constructor of the class, in case the + // string constant or class constant is being used in a Class.forName + // or a .class construct. + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, + parameterlessConstructorMarker); } @@ -915,6 +1047,6 @@ implements ClassVisitor, */ private void markConstant(Clazz clazz, int index) { - clazz.constantPoolEntryAccept(index, this); + clazz.constantPoolEntryAccept(index, this); } } diff --git a/src/proguard/shrink/UsagePrinter.java b/src/proguard/shrink/UsagePrinter.java index 294b9e1..69df7fa 100644 --- a/src/proguard/shrink/UsagePrinter.java +++ b/src/proguard/shrink/UsagePrinter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 @@ -21,6 +21,8 @@ package proguard.shrink; import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.*; import proguard.classfile.visitor.*; @@ -38,7 +40,8 @@ import java.io.PrintStream; public class UsagePrinter extends SimplifiedVisitor implements ClassVisitor, - MemberVisitor + MemberVisitor, + AttributeVisitor { private final UsageMarker usageMarker; private final boolean printUnusedItems; @@ -121,7 +124,6 @@ implements ClassVisitor, printClassNameHeader(); ps.println(" " + - lineNumberRange(programClass, programField) + ClassUtil.externalFullFieldDescription( programField.getAccessFlags(), programField.getName(programClass), @@ -136,9 +138,10 @@ implements ClassVisitor, { printClassNameHeader(); - ps.println(" " + - lineNumberRange(programClass, programMethod) + - ClassUtil.externalFullMethodDescription( + ps.print("===="); + ps.print(" "); + programMethod.attributesAccept(programClass, this); + ps.println(ClassUtil.externalFullMethodDescription( programClass.getName(), programMethod.getAccessFlags(), programMethod.getName(programClass), @@ -147,6 +150,24 @@ implements ClassVisitor, } + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) + { + ps.print(lineNumberTableAttribute.getLowestLineNumber() + ":" + + lineNumberTableAttribute.getHighestLineNumber() + ":"); + } + + // Small utility methods. /** @@ -161,17 +182,4 @@ implements ClassVisitor, className = null; } } - - - /** - * Returns the line number range of the given class member, followed by a - * colon, or just an empty String if no range is available. - */ - private static String lineNumberRange(ProgramClass programClass, ProgramMember programMember) - { - String range = programMember.getLineNumberRange(programClass); - return range != null ? - (range + ":") : - ""; - } } diff --git a/src/proguard/shrink/UsedClassFilter.java b/src/proguard/shrink/UsedClassFilter.java index ec180bd..7630b0b 100644 --- a/src/proguard/shrink/UsedClassFilter.java +++ b/src/proguard/shrink/UsedClassFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 diff --git a/src/proguard/shrink/UsedMemberFilter.java b/src/proguard/shrink/UsedMemberFilter.java index 755cfd1..f1a9c75 100644 --- a/src/proguard/shrink/UsedMemberFilter.java +++ b/src/proguard/shrink/UsedMemberFilter.java @@ -2,7 +2,7 @@ * ProGuard -- shrinking, optimization, obfuscation, and preverification * of Java bytecode. * - * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu) + * Copyright (c) 2002-2013 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 @@ -39,7 +39,7 @@ implements MemberVisitor /** - * Creates a new UsedClassFilter. + * Creates a new UsedMemberFilter. * @param usageMarker the usage marker that is used to mark the classes * and class members. * @param memberVisitor the member visitor to which the visiting will be |