diff options
Diffstat (limited to 'src/proguard/shrink/ClassShrinker.java')
-rw-r--r-- | src/proguard/shrink/ClassShrinker.java | 560 |
1 files changed, 0 insertions, 560 deletions
diff --git a/src/proguard/shrink/ClassShrinker.java b/src/proguard/shrink/ClassShrinker.java deleted file mode 100644 index 3c3a55e..0000000 --- a/src/proguard/shrink/ClassShrinker.java +++ /dev/null @@ -1,560 +0,0 @@ -/* - * ProGuard -- shrinking, optimization, obfuscation, and preverification - * of Java bytecode. - * - * 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 - * 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.annotation.*; -import proguard.classfile.attribute.annotation.visitor.*; -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, class members, and other - * class elements that are not marked as being used. - * - * @see UsageMarker - * - * @author Eric Lafortune - */ -public class ClassShrinker -extends SimplifiedVisitor -implements ClassVisitor, - MemberVisitor, - AttributeVisitor, - AnnotationVisitor, - ElementValueVisitor -{ - private final UsageMarker usageMarker; - - private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; - private int[] bootstrapMethodIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; - private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); - private final BootstrapMethodRemapper bootstrapMethodRemapper = new BootstrapMethodRemapper(); - - - /** - * Creates a new ClassShrinker. - * @param usageMarker the usage marker that is used to mark the classes - * and class members. - */ - public ClassShrinker(UsageMarker usageMarker) - { - this.usageMarker = usageMarker; - } - - - // Implementations for ClassVisitor. - - public void visitProgramClass(ProgramClass programClass) - { - // Shrink the arrays for constant pool, interfaces, fields, methods, - // and class attributes. - if (programClass.u2interfacesCount > 0) - { - new InterfaceDeleter(shrinkFlags(programClass.constantPool, - programClass.u2interfaces, - programClass.u2interfacesCount)) - .visitProgramClass(programClass); - } - - // Shrinking the constant pool also sets up an index map. - int newConstantPoolCount = - shrinkConstantPool(programClass.constantPool, - programClass.u2constantPoolCount); - - programClass.u2fieldsCount = - shrinkArray(programClass.fields, - programClass.u2fieldsCount); - - programClass.u2methodsCount = - shrinkArray(programClass.methods, - programClass.u2methodsCount); - - programClass.u2attributesCount = - shrinkArray(programClass.attributes, - programClass.u2attributesCount); - - // Compact the remaining fields, methods, and attributes, - // and remap their references to the constant pool. - programClass.fieldsAccept(this); - programClass.methodsAccept(this); - programClass.attributesAccept(this); - - // 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); - } - - // Replace any unused classes in the signatures. - MySignatureCleaner signatureCleaner = new MySignatureCleaner(); - programClass.fieldsAccept(new AllAttributeVisitor(signatureCleaner)); - programClass.methodsAccept(new AllAttributeVisitor(signatureCleaner)); - programClass.attributesAccept(signatureCleaner); - - // Compact the extra field pointing to the subclasses of this class. - programClass.subClasses = - shrinkToNewArray(programClass.subClasses); - } - - - public void visitLibraryClass(LibraryClass libraryClass) - { - // Library classes are left unchanged. - - // Compact the extra field pointing to the subclasses of this class. - libraryClass.subClasses = - shrinkToNewArray(libraryClass.subClasses); - } - - - // Implementations for MemberVisitor. - - public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) - { - // Shrink the attributes array. - programMember.u2attributesCount = - shrinkArray(programMember.attributes, - programMember.u2attributesCount); - - // Shrink any attributes. - programMember.attributesAccept(programClass, this); - } - - - // Implementations for AttributeVisitor. - - public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} - - - public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) - { - // Shrink the array of BootstrapMethodInfo objects. - int newBootstrapMethodsCount = - shrinkBootstrapMethodArray(bootstrapMethodsAttribute.bootstrapMethods, - bootstrapMethodsAttribute.u2bootstrapMethodsCount); - - if (newBootstrapMethodsCount < bootstrapMethodsAttribute.u2bootstrapMethodsCount) - { - bootstrapMethodsAttribute.u2bootstrapMethodsCount = newBootstrapMethodsCount; - - // Remap all constant pool references. - bootstrapMethodRemapper.setConstantIndexMap(bootstrapMethodIndexMap); - clazz.constantPoolEntriesAccept(bootstrapMethodRemapper); - } - } - - - public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) - { - // Shrink the array of InnerClassesInfo objects. - innerClassesAttribute.u2classesCount = - shrinkArray(innerClassesAttribute.classes, - innerClassesAttribute.u2classesCount); - } - - - public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) - { - // Sometimes, a class is still referenced (apparently as a dummy class), - // but its enclosing method is not. Then remove the reference to - // the enclosing method. - // E.g. the anonymous inner class javax.swing.JList$1 is defined inside - // a constructor of javax.swing.JList, but it is also referenced as a - // dummy argument in a constructor of javax.swing.JList$ListSelectionHandler. - if (enclosingMethodAttribute.referencedMethod != null && - !usageMarker.isUsed(enclosingMethodAttribute.referencedMethod)) - { - enclosingMethodAttribute.u2nameAndTypeIndex = 0; - - enclosingMethodAttribute.referencedMethod = null; - } - } - - - public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) - { - // Shrink the attributes array. - 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); - } - - - public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) - { - // Shrink the annotations array. - annotationsAttribute.u2annotationsCount = - shrinkArray(annotationsAttribute.annotations, - annotationsAttribute.u2annotationsCount); - - // Shrink the annotations themselves. - annotationsAttribute.annotationsAccept(clazz, this); - } - - - public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) - { - // Loop over all parameters. - for (int parameterIndex = 0; parameterIndex < parameterAnnotationsAttribute.u1parametersCount; parameterIndex++) - { - // Shrink the parameter annotations array. - parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex] = - shrinkArray(parameterAnnotationsAttribute.parameterAnnotations[parameterIndex], - parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex]); - } - - // Shrink the annotations themselves. - parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); - } - - - // Implementations for AnnotationVisitor. - - public void visitAnnotation(Clazz clazz, Annotation annotation) - { - // Shrink the element values array. - annotation.u2elementValuesCount = - shrinkArray(annotation.elementValues, - annotation.u2elementValuesCount); - - // Shrink the element values themselves. - annotation.elementValuesAccept(clazz, this); - } - - - /** - * This AttributeVisitor updates the Utf8 constants of signatures - * of classes, fields, and methods. - */ - private class MySignatureCleaner - extends SimplifiedVisitor - implements AttributeVisitor - { - public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} - - - public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) - { - Clazz[] referencedClasses = signatureAttribute.referencedClasses; - if (referencedClasses != null) - { - // Go over the classes in the signature. - String signature = signatureAttribute.getSignature(clazz); - - DescriptorClassEnumeration classEnumeration = - new DescriptorClassEnumeration(signature); - - int referencedClassIndex = 0; - - // Start construction a new signature. - StringBuffer newSignatureBuffer = new StringBuffer(); - - newSignatureBuffer.append(classEnumeration.nextFluff()); - - while (classEnumeration.hasMoreClassNames()) - { - String className = classEnumeration.nextClassName(); - - // Replace the class name if it is unused. - Clazz referencedClass = referencedClasses[referencedClassIndex]; - if (referencedClass != null && - !usageMarker.isUsed(referencedClass)) - { - className = ClassConstants.NAME_JAVA_LANG_OBJECT; - - referencedClasses[referencedClassIndex] = null; - } - - referencedClassIndex++; - - newSignatureBuffer.append(className); - newSignatureBuffer.append(classEnumeration.nextFluff()); - } - - // Update the signature. - ((Utf8Constant)((ProgramClass)clazz).constantPool[signatureAttribute.u2signatureIndex]).setString(newSignatureBuffer.toString()); - } - } - } - - - // Implementations for ElementValueVisitor. - - public void visitAnyElementValue(Clazz clazz, Annotation annotation, ElementValue elementValue) {} - - - public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) - { - // Shrink the contained annotation. - annotationElementValue.annotationAccept(clazz, this); - } - - - public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) - { - // Shrink the element values array. - arrayElementValue.u2elementValuesCount = - shrinkArray(arrayElementValue.elementValues, - arrayElementValue.u2elementValuesCount); - - // Shrink the element values themselves. - arrayElementValue.elementValuesAccept(clazz, annotation, this); - } - - - // Small utility methods. - - /** - * Removes all entries that are not marked as being used from the given - * constant pool. Creates a map from the old indices to the new indices - * as a side effect. - * @return the new number of entries. - */ - private int shrinkConstantPool(Constant[] constantPool, int length) - { - if (constantIndexMap.length < length) - { - constantIndexMap = new int[length]; - } - - int counter = 1; - boolean isUsed = false; - - // Shift the used constant pool entries together. - for (int index = 1; index < length; index++) - { - constantIndexMap[index] = counter; - - Constant constant = constantPool[index]; - - // Is the constant being used? Don't update the flag if this is the - // second half of a long entry. - if (constant != null) - { - isUsed = usageMarker.isUsed(constant); - } - - if (isUsed) - { - // Remember the new index. - constantIndexMap[index] = counter; - - // Shift the constant pool entry. - constantPool[counter++] = constant; - } - else - { - // Remember an invalid index. - constantIndexMap[index] = -1; - } - } - - // Clear the remaining constant pool elements. - Arrays.fill(constantPool, counter, length, null); - - return counter; - } - - - /** - * Creates an array marking unused constant pool entries for all the - * elements in the given array of constant pool indices. - * @return an array of flags indicating unused elements. - */ - private boolean[] shrinkFlags(Constant[] constantPool, int[] array, int length) - { - boolean[] unused = new boolean[length]; - - // Shift the used objects together. - for (int index = 0; index < length; index++) - { - if (!usageMarker.isUsed(constantPool[array[index]])) - { - unused[index] = true; - } - } - - return unused; - } - - - /** - * Removes all indices that point to unused constant pool entries - * from the given array. - * @return the new number of indices. - */ - private int shrinkConstantIndexArray(Constant[] constantPool, int[] array, int length) - { - int counter = 0; - - // Shift the used objects together. - for (int index = 0; index < length; index++) - { - if (usageMarker.isUsed(constantPool[array[index]])) - { - array[counter++] = array[index]; - } - } - - // Clear the remaining array elements. - Arrays.fill(array, counter, length, 0); - - return counter; - } - - - /** - * Removes all Clazz objects that are not marked as being used - * from the given array and returns the remaining objects in a an array - * of the right size. - * @return the new array. - */ - private Clazz[] shrinkToNewArray(Clazz[] array) - { - if (array == null) - { - return null; - } - - // Shrink the given array in-place. - int length = shrinkArray(array, array.length); - if (length == 0) - { - return null; - } - - // Return immediately if the array is of right size already. - if (length == array.length) - { - return array; - } - - // Copy the remaining elements into a new array of the right size. - Clazz[] newArray = new Clazz[length]; - System.arraycopy(array, 0, newArray, 0, length); - return newArray; - } - - - /** - * Removes all entries that are not marked as being used from the given - * array of bootstrap methods. Creates a map from the old indices to the - * new indices as a side effect. - * @return the new number of entries. - */ - private int shrinkBootstrapMethodArray(BootstrapMethodInfo[] bootstrapMethods, int length) - { - if (bootstrapMethodIndexMap.length < length) - { - bootstrapMethodIndexMap = new int[length]; - } - - int counter = 0; - - // Shift the used bootstrap methods together. - for (int index = 0; index < length; index++) - { - BootstrapMethodInfo bootstrapMethod = bootstrapMethods[index]; - - // Is the entry being used? - if (usageMarker.isUsed(bootstrapMethod)) - { - // Remember the new index. - bootstrapMethodIndexMap[index] = counter; - - // Shift the entry. - bootstrapMethods[counter++] = bootstrapMethod; - } - else - { - // Remember an invalid index. - bootstrapMethodIndexMap[index] = -1; - } - } - - // Clear the remaining bootstrap methods. - Arrays.fill(bootstrapMethods, counter, length, null); - - return counter; - } - - - /** - * Removes all VisitorAccepter objects that are not marked as being used - * from the given array. - * @return the new number of VisitorAccepter objects. - */ - private int shrinkArray(VisitorAccepter[] array, int length) - { - int counter = 0; - - // Shift the used objects together. - for (int index = 0; index < length; index++) - { - VisitorAccepter visitorAccepter = array[index]; - - if (usageMarker.isUsed(visitorAccepter)) - { - array[counter++] = visitorAccepter; - } - } - - // Clear any remaining array elements. - if (counter < length) - { - Arrays.fill(array, counter, length, null); - } - - return counter; - } -} |