diff options
author | Ying Wang <wangying@google.com> | 2012-02-27 10:21:35 -0800 |
---|---|---|
committer | Ying Wang <wangying@google.com> | 2012-02-27 11:54:51 -0800 |
commit | cfead78069f3dc32998dc118ee08cab3867acea2 (patch) | |
tree | 9600f15eed62fa9ba63ce5894d1f09fe686d5997 /src/proguard/classfile/editor | |
parent | 10aa7224f49abe49d123bde5d34346202d49aaca (diff) | |
download | android_external_proguard-cfead78069f3dc32998dc118ee08cab3867acea2.tar.gz android_external_proguard-cfead78069f3dc32998dc118ee08cab3867acea2.tar.bz2 android_external_proguard-cfead78069f3dc32998dc118ee08cab3867acea2.zip |
Upgrade from Progaurd 4.4 to 4.7.
Change-Id: Ie185d0be411a80cc6a330cafa8547252a7dc1d9c
You can find the changelog here
http://proguard.sourceforge.net/#downloads.html
Diffstat (limited to 'src/proguard/classfile/editor')
51 files changed, 2235 insertions, 411 deletions
diff --git a/src/proguard/classfile/editor/AccessFixer.java b/src/proguard/classfile/editor/AccessFixer.java index 7d6274e..8ff08f3 100644 --- a/src/proguard/classfile/editor/AccessFixer.java +++ b/src/proguard/classfile/editor/AccessFixer.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-2011 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.classfile.editor; 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.*; @@ -61,12 +63,26 @@ implements ConstantVisitor, } + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + // Check the bootstrap method. + invokeDynamicConstant.bootstrapMethodHandleAccept(clazz, this); + } + + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + // Check the method reference. + clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); + } + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { referencingClass = clazz; // Remember the specified class, since it might be different from - // the referenced class that acutally contains the class member. + // the referenced class that actually contains the class member. clazz.constantPoolEntryAccept(refConstant.u2classIndex, referencedClassFinder); // Make sure the access flags of the referenced class member are @@ -91,8 +107,8 @@ implements ConstantVisitor, public void visitProgramClass(ProgramClass programClass) { - int currentAccessFlags = programClass.getAccessFlags(); - int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); + int currentAccessFlags = programClass.getAccessFlags(); + int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); // Compute the required access level. Clazz referencingClass = this.referencingClass; @@ -117,8 +133,8 @@ implements ConstantVisitor, public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) { - int currentAccessFlags = programMember.getAccessFlags(); - int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); + int currentAccessFlags = programMember.getAccessFlags(); + int currentAccessLevel = AccessUtil.accessLevel(currentAccessFlags); // Compute the required access level. int requiredAccessLevel = diff --git a/src/proguard/classfile/editor/AnnotationAdder.java b/src/proguard/classfile/editor/AnnotationAdder.java index 359164a..3c35608 100644 --- a/src/proguard/classfile/editor/AnnotationAdder.java +++ b/src/proguard/classfile/editor/AnnotationAdder.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-2011 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/classfile/editor/AnnotationsAttributeEditor.java b/src/proguard/classfile/editor/AnnotationsAttributeEditor.java index bf8852c..5537f5e 100644 --- a/src/proguard/classfile/editor/AnnotationsAttributeEditor.java +++ b/src/proguard/classfile/editor/AnnotationsAttributeEditor.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-2011 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/classfile/editor/AttributeAdder.java b/src/proguard/classfile/editor/AttributeAdder.java index 2b610b7..a7f8dc3 100644 --- a/src/proguard/classfile/editor/AttributeAdder.java +++ b/src/proguard/classfile/editor/AttributeAdder.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-2011 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 @@ -256,7 +256,7 @@ implements AttributeVisitor CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(); - codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); + codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength + 32); // Add the instructions. codeAttribute.instructionsAccept(clazz, diff --git a/src/proguard/classfile/editor/AttributeSorter.java b/src/proguard/classfile/editor/AttributeSorter.java index d8e3367..dcae85e 100644 --- a/src/proguard/classfile/editor/AttributeSorter.java +++ b/src/proguard/classfile/editor/AttributeSorter.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-2011 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/classfile/editor/AttributesEditor.java b/src/proguard/classfile/editor/AttributesEditor.java index 10846cc..91c0080 100644 --- a/src/proguard/classfile/editor/AttributesEditor.java +++ b/src/proguard/classfile/editor/AttributesEditor.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-2011 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/classfile/editor/BridgeMethodFixer.java b/src/proguard/classfile/editor/BridgeMethodFixer.java new file mode 100644 index 0000000..010c8a2 --- /dev/null +++ b/src/proguard/classfile/editor/BridgeMethodFixer.java @@ -0,0 +1,117 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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.classfile.editor; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.*; +import proguard.classfile.visitor.*; + +/** + * This MemberVisitor fixes all inappropriate bridge access flags of the + * program methods that it visits, checking whether the methods to which they + * bridge have the same name. Some compilers, like in Eclipse and in later + * versions of JDK 1.6, complain if they can't find the method with the same + * name. + * + * @author Eric Lafortune + */ +public class BridgeMethodFixer +extends SimplifiedVisitor +implements MemberVisitor, + AttributeVisitor, + InstructionVisitor, + ConstantVisitor +{ + private static final boolean DEBUG = false; + + + // Return values for the visitor methods. + private String bridgedMethodName; + + + // Implementations for MemberVisitor. + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + if ((programMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_BRIDGE) != 0) + { + programMethod.attributesAccept(programClass, this); + } + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + // Go over the instructions of the bridge method. + codeAttribute.instructionsAccept(clazz, method, this); + } + + + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + switch (constantInstruction.opcode) + { + case InstructionConstants.OP_INVOKEVIRTUAL: + case InstructionConstants.OP_INVOKESPECIAL: + case InstructionConstants.OP_INVOKESTATIC: + case InstructionConstants.OP_INVOKEINTERFACE: + // Get the name of the bridged method. + clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); + + // Check if the name is different. + if (!method.getName(clazz).equals(bridgedMethodName)) + { + if (DEBUG) + { + System.out.println("BridgeMethodFixer: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"] does not bridge to ["+bridgedMethodName+"]"); + } + + // Clear the bridge flag. + ((ProgramMethod)method).u2accessFlags &= ~ClassConstants.INTERNAL_ACC_BRIDGE; + } + break; + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) + { + bridgedMethodName = refConstant.getName(clazz); + } +}
\ No newline at end of file diff --git a/src/proguard/classfile/editor/ClassEditor.java b/src/proguard/classfile/editor/ClassEditor.java index e503ea3..f51ae45 100644 --- a/src/proguard/classfile/editor/ClassEditor.java +++ b/src/proguard/classfile/editor/ClassEditor.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-2011 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/classfile/editor/ClassElementSorter.java b/src/proguard/classfile/editor/ClassElementSorter.java index 3256c88..c5eb366 100644 --- a/src/proguard/classfile/editor/ClassElementSorter.java +++ b/src/proguard/classfile/editor/ClassElementSorter.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-2011 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/classfile/editor/ClassMemberSorter.java b/src/proguard/classfile/editor/ClassMemberSorter.java index f31fcd0..61d69b2 100644 --- a/src/proguard/classfile/editor/ClassMemberSorter.java +++ b/src/proguard/classfile/editor/ClassMemberSorter.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-2011 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/classfile/editor/ClassReferenceFixer.java b/src/proguard/classfile/editor/ClassReferenceFixer.java index 9857903..808d339 100644 --- a/src/proguard/classfile/editor/ClassReferenceFixer.java +++ b/src/proguard/classfile/editor/ClassReferenceFixer.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-2011 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/classfile/editor/CodeAttributeComposer.java b/src/proguard/classfile/editor/CodeAttributeComposer.java index e783203..a645f57 100644 --- a/src/proguard/classfile/editor/CodeAttributeComposer.java +++ b/src/proguard/classfile/editor/CodeAttributeComposer.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-2011 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 @@ -29,6 +29,8 @@ import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; +import java.util.Arrays; + /** * This AttributeVisitor accumulates instructions and exceptions, and then * copies them into code attributes that it visits. @@ -49,7 +51,7 @@ implements AttributeVisitor, //* private static final boolean DEBUG = false; /*/ - public static boolean DEBUG = true; + public static boolean DEBUG = false; //*/ @@ -313,7 +315,7 @@ implements AttributeVisitor, int handlerPC = -exceptionInfo.u2handlerPC; if (handlerPC > 0) { - if (remappableInstructionOffset(handlerPC)) + if (remappableExceptionHandler(handlerPC)) { exceptionInfo.u2handlerPC = remapInstructionOffset(handlerPC); } @@ -490,7 +492,7 @@ implements AttributeVisitor, int handlerPC = exceptionInfo.u2handlerPC; exceptionInfo.u2handlerPC = !allowExternalExceptionHandlers || - remappableInstructionOffset(handlerPC) ? + remappableExceptionHandler(handlerPC) ? remapInstructionOffset(handlerPC) : -handlerPC; } @@ -674,13 +676,21 @@ implements AttributeVisitor, /** - * Returns whether the given old instruction offset can be remapped at the + * Returns whether the given old exception handler can be remapped in the + * current code fragment. */ - private boolean remappableInstructionOffset(int oldInstructionOffset) + private boolean remappableExceptionHandler(int oldInstructionOffset) { - return - oldInstructionOffset <= codeFragmentLengths[level] && - instructionOffsetMap[level][oldInstructionOffset] > INVALID; + if (oldInstructionOffset > codeFragmentLengths[level]) + { + return false; + } + + int newInstructionOffset = + instructionOffsetMap[level][oldInstructionOffset]; + + return newInstructionOffset > INVALID && + newInstructionOffset < codeLength; } @@ -703,10 +713,7 @@ implements AttributeVisitor, } // Clear the unused array entries. - for (int index = newIndex; index < exceptionInfoCount; index++) - { - exceptionInfos[index] = null; - } + Arrays.fill(exceptionInfos, newIndex, exceptionInfoCount, null); return newIndex; } @@ -734,10 +741,7 @@ implements AttributeVisitor, } // Clear the unused array entries. - for (int index = newIndex; index < lineNumberInfoCount; index++) - { - lineNumberInfos[index] = null; - } + Arrays.fill(lineNumberInfos, newIndex, lineNumberInfoCount, null); return newIndex; } @@ -764,10 +768,7 @@ implements AttributeVisitor, } // Clear the unused array entries. - for (int index = newIndex; index < localVariableInfoCount; index++) - { - localVariableInfos[index] = null; - } + Arrays.fill(localVariableInfos, newIndex, localVariableInfoCount, null); return newIndex; } @@ -794,10 +795,7 @@ implements AttributeVisitor, } // Clear the unused array entries. - for (int index = newIndex; index < localVariableTypeInfoCount; index++) - { - localVariableTypeInfos[index] = null; - } + Arrays.fill(localVariableTypeInfos, newIndex, localVariableTypeInfoCount, null); return newIndex; } diff --git a/src/proguard/classfile/editor/CodeAttributeEditor.java b/src/proguard/classfile/editor/CodeAttributeEditor.java index 9658c98..82ed29e 100644 --- a/src/proguard/classfile/editor/CodeAttributeEditor.java +++ b/src/proguard/classfile/editor/CodeAttributeEditor.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-2011 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 @@ -28,7 +28,8 @@ import proguard.classfile.attribute.visitor.*; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.SimplifiedVisitor; -import proguard.classfile.visitor.ClassPrinter; + +import java.util.Arrays; /** * This AttributeVisitor accumulates specified changes to code, and then applies @@ -105,13 +106,10 @@ implements AttributeVisitor, } else { - for (int index = 0; index < codeLength; index++) - { - preInsertions[index] = null; - replacements[index] = null; - postInsertions[index] = null; - deleted[index] = false; - } + Arrays.fill(preInsertions, 0, codeLength, null); + Arrays.fill(replacements, 0, codeLength, null); + Arrays.fill(postInsertions, 0, codeLength, null); + Arrays.fill(deleted, 0, codeLength, false); } modified = false; @@ -328,52 +326,51 @@ implements AttributeVisitor, { if (DEBUG) { - System.out.println("CodeAttributeEditor: ["+clazz.getName()+"."+method.getName(clazz)+"]"); + System.out.println("CodeAttributeEditor: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); } - // Avoid doing any work if nothing is changing anyway. - if (!modified) + // Do we have to update the code? + if (modified) { - return; - } - - // Check if we can perform a faster simple replacement of instructions. - if (canPerformSimpleReplacements(codeAttribute)) - { - // Simply overwrite the instructions. - performSimpleReplacements(codeAttribute); + // Can we perform a faster simple replacement of instructions? + if (canPerformSimpleReplacements(codeAttribute)) + { + if (DEBUG) + { + System.out.println(" Simple editing"); + } - // Update the maximum stack size and local variable frame size. - updateFrameSizes(clazz, method, codeAttribute); - } - else - { - // Move and remap the instructions. - codeAttribute.u4codeLength = - updateInstructions(clazz, method, codeAttribute); + // Simply overwrite the instructions. + performSimpleReplacements(codeAttribute); + } + else + { + if (DEBUG) + { + System.out.println(" Full editing"); + } - // Remap the exception table. - codeAttribute.exceptionsAccept(clazz, method, this); + // Move and remap the instructions. + codeAttribute.u4codeLength = + updateInstructions(clazz, method, codeAttribute); - // Remove exceptions with empty code blocks. - codeAttribute.u2exceptionTableLength = - removeEmptyExceptions(codeAttribute.exceptionTable, - codeAttribute.u2exceptionTableLength); + // Remap the exception table. + codeAttribute.exceptionsAccept(clazz, method, this); - // Update the maximum stack size and local variable frame size. - updateFrameSizes(clazz, method, codeAttribute); + // Remove exceptions with empty code blocks. + codeAttribute.u2exceptionTableLength = + removeEmptyExceptions(codeAttribute.exceptionTable, + codeAttribute.u2exceptionTableLength); - // Remap the line number table and the local variable table. - codeAttribute.attributesAccept(clazz, method, this); + // Remap the line number table and the local variable tables. + codeAttribute.attributesAccept(clazz, method, this); + } // Make sure instructions are widened if necessary. instructionWriter.visitCodeAttribute(clazz, method, codeAttribute); } - } - - private void updateFrameSizes(Clazz clazz, Method method, CodeAttribute codeAttribute) - { + // Update the maximum stack size and local variable frame size. if (updateFrameSizes) { stackSizeUpdater.visitCodeAttribute(clazz, method, codeAttribute); @@ -415,12 +412,6 @@ implements AttributeVisitor, { // Remap all local variable table entries. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - - // Remove local variables with empty code blocks. - localVariableTableAttribute.u2localVariableTableLength = - removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable, - localVariableTableAttribute.u2localVariableTableLength, - codeAttribute.u2maxLocals); } @@ -428,12 +419,6 @@ implements AttributeVisitor, { // Remap all local variable table entries. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - - // Remove local variables with empty code blocks. - localVariableTypeTableAttribute.u2localVariableTypeTableLength = - removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, - localVariableTypeTableAttribute.u2localVariableTypeTableLength, - codeAttribute.u2maxLocals); } @@ -912,10 +897,12 @@ implements AttributeVisitor, public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) { // Remap the code offset and length. - // TODO: The local variable frame might not be strictly preserved. - localVariableInfo.u2length = remapBranchOffset(localVariableInfo.u2startPC, - localVariableInfo.u2length); - localVariableInfo.u2startPC = remapInstructionOffset(localVariableInfo.u2startPC); + int newStartPC = remapInstructionOffset(localVariableInfo.u2startPC); + int newEndPC = remapInstructionOffset(localVariableInfo.u2startPC + + localVariableInfo.u2length); + + localVariableInfo.u2length = newEndPC - newStartPC; + localVariableInfo.u2startPC = newStartPC; } @@ -924,10 +911,12 @@ implements AttributeVisitor, public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) { // Remap the code offset and length. - // TODO: The local variable frame might not be strictly preserved. - localVariableTypeInfo.u2length = remapBranchOffset(localVariableTypeInfo.u2startPC, - localVariableTypeInfo.u2length); - localVariableTypeInfo.u2startPC = remapInstructionOffset(localVariableTypeInfo.u2startPC); + int newStartPC = remapInstructionOffset(localVariableTypeInfo.u2startPC); + int newEndPC = remapInstructionOffset(localVariableTypeInfo.u2startPC + + localVariableTypeInfo.u2length); + + localVariableTypeInfo.u2length = newEndPC - newStartPC; + localVariableTypeInfo.u2startPC = newStartPC; } @@ -1017,54 +1006,6 @@ implements AttributeVisitor, } - /** - * Returns the given list of local variables, without the ones that have empty - * code blocks or that exceed the actual number of local variables. - */ - private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos, - int localVariableInfoCount, - int maxLocals) - { - // Overwrite all empty local variable entries. - int newIndex = 0; - for (int index = 0; index < localVariableInfoCount; index++) - { - LocalVariableInfo localVariableInfo = localVariableInfos[index]; - if (localVariableInfo.u2length > 0 && - localVariableInfo.u2index < maxLocals) - { - localVariableInfos[newIndex++] = localVariableInfo; - } - } - - return newIndex; - } - - - /** - * Returns the given list of local variable types, without the ones that - * have empty code blocks or that exceed the actual number of local variables. - */ - private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, - int localVariableTypeInfoCount, - int maxLocals) - { - // Overwrite all empty local variable type entries. - int newIndex = 0; - for (int index = 0; index < localVariableTypeInfoCount; index++) - { - LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; - if (localVariableTypeInfo.u2length > 0 && - localVariableTypeInfo.u2index < maxLocals) - { - localVariableTypeInfos[newIndex++] = localVariableTypeInfo; - } - } - - return newIndex; - } - - private class CompositeInstruction extends Instruction { diff --git a/src/proguard/classfile/editor/CodeAttributeEditorResetter.java b/src/proguard/classfile/editor/CodeAttributeEditorResetter.java index 9962ea5..eedc045 100644 --- a/src/proguard/classfile/editor/CodeAttributeEditorResetter.java +++ b/src/proguard/classfile/editor/CodeAttributeEditorResetter.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-2011 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/classfile/editor/ComparableConstant.java b/src/proguard/classfile/editor/ComparableConstant.java index bb81221..ba5f3b1 100644 --- a/src/proguard/classfile/editor/ComparableConstant.java +++ b/src/proguard/classfile/editor/ComparableConstant.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-2011 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 @@ class ComparableConstant extends SimplifiedVisitor implements Comparable, ConstantVisitor { - private static final int[] PRIORITIES = new int[13]; + private static final int[] PRIORITIES = new int[19]; static { PRIORITIES[ClassConstants.CONSTANT_Integer] = 0; // Possibly byte index (ldc). @@ -47,12 +47,15 @@ implements Comparable, ConstantVisitor PRIORITIES[ClassConstants.CONSTANT_String] = 2; PRIORITIES[ClassConstants.CONSTANT_Class] = 3; PRIORITIES[ClassConstants.CONSTANT_Long] = 4; // Always wide index (ldc2_w). - PRIORITIES[ClassConstants.CONSTANT_Double] = 5; - PRIORITIES[ClassConstants.CONSTANT_Fieldref] = 6; // Always wide index. - PRIORITIES[ClassConstants.CONSTANT_Methodref] = 7; - PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 8; - PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 9; - PRIORITIES[ClassConstants.CONSTANT_Utf8] = 10; + PRIORITIES[ClassConstants.CONSTANT_Double] = 5; // Always wide index (ldc2_w). + PRIORITIES[ClassConstants.CONSTANT_Fieldref] = 6; // Always wide index (getfield,...). + PRIORITIES[ClassConstants.CONSTANT_Methodref] = 7; // Always wide index (invokespecial,...). + PRIORITIES[ClassConstants.CONSTANT_InterfaceMethodref] = 8; // Always wide index (invokeinterface). + PRIORITIES[ClassConstants.CONSTANT_InvokeDynamic] = 9; // Always wide index (invokedynamic). + PRIORITIES[ClassConstants.CONSTANT_MethodHandle] = 10; + PRIORITIES[ClassConstants.CONSTANT_NameAndType] = 11; + PRIORITIES[ClassConstants.CONSTANT_MethodType] = 12; + PRIORITIES[ClassConstants.CONSTANT_Utf8] = 13; } private final Clazz clazz; @@ -122,26 +125,32 @@ implements Comparable, ConstantVisitor public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { - // In JDK 1.4, we can use Integer.compare(a,b). - result = new Integer(integerConstant.getValue()).compareTo(new Integer(((IntegerConstant)otherConstant).getValue())); + int value = integerConstant.getValue(); + int otherValue = ((IntegerConstant)otherConstant).getValue(); + result = value < otherValue ? -1 : + value == otherValue ? 0 : + 1; } public void visitLongConstant(Clazz clazz, LongConstant longConstant) { - // In JDK 1.4, we can use Long.compare(a,b). - result = new Long(longConstant.getValue()).compareTo(new Long(((LongConstant)otherConstant).getValue())); + long value = longConstant.getValue(); + long otherValue = ((LongConstant)otherConstant).getValue(); + result = value < otherValue ? -1 : + value == otherValue ? 0 : + 1; } public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { - // In JDK 1.4, we can use Float.compare(a,b). - result = new Float(floatConstant.getValue()).compareTo(new Float(((FloatConstant)otherConstant).getValue())); + result = Float.compare(floatConstant.getValue(), + ((FloatConstant)otherConstant).getValue()); } public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) - { - // In JDK 1.4, we can use Double.compare(a,b). - result = new Double(doubleConstant.getValue()).compareTo(new Double(((DoubleConstant)otherConstant).getValue())); + { + result = Double.compare(doubleConstant.getValue(), + ((DoubleConstant)otherConstant).getValue()); } public void visitStringConstant(Clazz clazz, StringConstant stringConstant) @@ -154,6 +163,38 @@ implements Comparable, ConstantVisitor result = utf8Constant.getString().compareTo(((Utf8Constant)otherConstant).getString()); } + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + InvokeDynamicConstant otherInvokeDynamicConstant = (InvokeDynamicConstant)otherConstant; + + int index = invokeDynamicConstant.getBootstrapMethodAttributeIndex(); + int otherIndex = otherInvokeDynamicConstant.getBootstrapMethodAttributeIndex(); + + result = index < otherIndex ? -1 : + index > otherIndex ? 1 : + (invokeDynamicConstant.getName(clazz) + ' ' + + invokeDynamicConstant.getType(clazz)) + .compareTo + (otherInvokeDynamicConstant.getName(clazz) + ' ' + + otherInvokeDynamicConstant.getType(clazz)); + } + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + MethodHandleConstant otherMethodHandleConstant = (MethodHandleConstant)otherConstant; + + int kind = methodHandleConstant.getReferenceKind(); + int otherKind = methodHandleConstant.getReferenceKind(); + + result = kind < otherKind ? -1 : + kind > otherKind ? 1 : + (methodHandleConstant.getName(clazz) + ' ' + + methodHandleConstant.getType(clazz)) + .compareTo + (otherMethodHandleConstant.getName(clazz) + ' ' + + otherMethodHandleConstant.getType(clazz)); + } + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) { RefConstant otherRefConstant = (RefConstant)otherConstant; @@ -171,6 +212,14 @@ implements Comparable, ConstantVisitor result = classConstant.getName(clazz).compareTo(((ClassConstant)otherConstant).getName(clazz)); } + public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant MethodTypeConstant) + { + MethodTypeConstant otherMethodTypeConstant = (MethodTypeConstant)otherConstant; + result = MethodTypeConstant.getType(clazz) + .compareTo + (otherMethodTypeConstant.getType(clazz)); + } + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { NameAndTypeConstant otherNameAndTypeConstant = (NameAndTypeConstant)otherConstant; diff --git a/src/proguard/classfile/editor/ConstantAdder.java b/src/proguard/classfile/editor/ConstantAdder.java index 2b74f5f..14edbce 100644 --- a/src/proguard/classfile/editor/ConstantAdder.java +++ b/src/proguard/classfile/editor/ConstantAdder.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-2011 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 @@ -23,6 +23,7 @@ package proguard.classfile.editor; import proguard.classfile.*; import proguard.classfile.constant.*; import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.util.ListUtil; /** * This ConstantVisitor adds all constants that it visits to the constant pool @@ -128,6 +129,43 @@ implements ConstantVisitor } + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + // First add the name and type constant. + clazz.constantPoolEntryAccept(invokeDynamicConstant.u2nameAndTypeIndex, this); + + // Copy the referenced classes. + Clazz[] referencedClasses = invokeDynamicConstant.referencedClasses; + Clazz[] referencedClassesCopy = null; + if (referencedClasses != null) + { + referencedClassesCopy = new Clazz[referencedClasses.length]; + System.arraycopy(referencedClasses, 0, + referencedClassesCopy, 0, + referencedClasses.length); + } + + // Then add the actual invoke dynamic constant. + constantIndex = + constantPoolEditor.addInvokeDynamicConstant(invokeDynamicConstant.getBootstrapMethodAttributeIndex(), + constantIndex, + referencedClassesCopy); + } + + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + // First add the field ref, interface method ref, or method ref + // constant. + clazz.constantPoolEntryAccept(methodHandleConstant.u2referenceIndex, this); + + // Then add the actual method handle constant. + constantIndex = + constantPoolEditor.addMethodHandleConstant(methodHandleConstant.getReferenceKind(), + constantIndex); + } + + public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) { // First add the referenced class constant, with its own referenced class. @@ -185,6 +223,13 @@ implements ConstantVisitor } + public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) + { + constantIndex = + constantPoolEditor.addMethodTypeConstant(methodTypeConstant.getType(clazz)); + } + + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { constantIndex = diff --git a/src/proguard/classfile/editor/ConstantPoolEditor.java b/src/proguard/classfile/editor/ConstantPoolEditor.java index 8663dee..6ba4857 100644 --- a/src/proguard/classfile/editor/ConstantPoolEditor.java +++ b/src/proguard/classfile/editor/ConstantPoolEditor.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-2011 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 @@ -199,6 +199,93 @@ public class ConstantPoolEditor /** + * Finds or creates a InvokeDynamicConstant constant pool entry with the + * given bootstrap method constant pool entry index, method name, and + * descriptor. + * @return the constant pool index of the InvokeDynamicConstant. + */ + public int addInvokeDynamicConstant(int bootstrapMethodIndex, + String name, + String descriptor, + Clazz[] referencedClasses) + { + return addInvokeDynamicConstant(bootstrapMethodIndex, + addNameAndTypeConstant(name, descriptor), + referencedClasses); + } + + + /** + * Finds or creates a InvokeDynamicConstant constant pool entry with the given + * class constant pool entry index and name and type constant pool entry + * index. + * @return the constant pool index of the InvokeDynamicConstant. + */ + public int addInvokeDynamicConstant(int bootstrapMethodIndex, + int nameAndTypeIndex, + Clazz[] referencedClasses) + { + int constantPoolCount = targetClass.u2constantPoolCount; + Constant[] constantPool = targetClass.constantPool; + + // Check if the entry already exists. + for (int index = 1; index < constantPoolCount; index++) + { + Constant constant = constantPool[index]; + + if (constant != null && + constant.getTag() == ClassConstants.CONSTANT_InvokeDynamic) + { + InvokeDynamicConstant invokeDynamicConstant = (InvokeDynamicConstant)constant; + if (invokeDynamicConstant.u2bootstrapMethodAttributeIndex == bootstrapMethodIndex && + invokeDynamicConstant.u2nameAndTypeIndex == nameAndTypeIndex) + { + return index; + } + } + } + + return addConstant(new InvokeDynamicConstant(bootstrapMethodIndex, + nameAndTypeIndex, + referencedClasses)); + } + + + /** + * Finds or creates a MethodHandleConstant constant pool entry of the + * specified kind and with the given field ref, interface method ref, + * or method ref constant pool entry index. + * @return the constant pool index of the MethodHandleConstant. + */ + public int addMethodHandleConstant(int referenceKind, + int referenceIndex) + { + int constantPoolCount = targetClass.u2constantPoolCount; + Constant[] constantPool = targetClass.constantPool; + + // Check if the entry already exists. + for (int index = 1; index < constantPoolCount; index++) + { + Constant constant = constantPool[index]; + + if (constant != null && + constant.getTag() == ClassConstants.CONSTANT_MethodHandle) + { + MethodHandleConstant methodHandleConstant = (MethodHandleConstant)constant; + if (methodHandleConstant.u1referenceKind == referenceKind && + methodHandleConstant.u2referenceIndex == referenceIndex) + { + return index; + } + } + } + + return addConstant(new MethodHandleConstant(referenceKind, + referenceIndex)); + } + + + /** * Finds or creates a FieldrefConstant constant pool entry for the given * class and field. * @return the constant pool index of the FieldrefConstant. @@ -563,6 +650,36 @@ public class ConstantPoolEditor /** + * Finds or creates a MethodTypeConstant constant pool entry with the given + * type. + * @return the constant pool index of the MethodTypeConstant. + */ + public int addMethodTypeConstant(String type) + { + int constantPoolCount = targetClass.u2constantPoolCount; + Constant[] constantPool = targetClass.constantPool; + + // Check if the entry already exists. + for (int index = 1; index < constantPoolCount; index++) + { + Constant constant = constantPool[index]; + + if (constant != null && + constant.getTag() == ClassConstants.CONSTANT_MethodType) + { + MethodTypeConstant methodTypeConstant = (MethodTypeConstant)constant; + if (methodTypeConstant.getType(targetClass).equals(type)) + { + return index; + } + } + } + + return addConstant(new MethodTypeConstant(addUtf8Constant(type))); + } + + + /** * Finds or creates a NameAndTypeConstant constant pool entry with the given * name and type. * @return the constant pool index of the NameAndTypeConstant. diff --git a/src/proguard/classfile/editor/ConstantPoolRemapper.java b/src/proguard/classfile/editor/ConstantPoolRemapper.java index 7430d3d..7677218 100644 --- a/src/proguard/classfile/editor/ConstantPoolRemapper.java +++ b/src/proguard/classfile/editor/ConstantPoolRemapper.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-2011 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 @@ -47,9 +47,10 @@ implements ClassVisitor, ConstantVisitor, MemberVisitor, AttributeVisitor, - InstructionVisitor, + BootstrapMethodInfoVisitor, InnerClassesInfoVisitor, ExceptionInfoVisitor, + InstructionVisitor, StackMapFrameVisitor, VerificationTypeVisitor, LocalVariableInfoVisitor, @@ -57,7 +58,7 @@ implements ClassVisitor, AnnotationVisitor, ElementValueVisitor { - private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); + private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(false); private int[] constantIndexMap; @@ -100,40 +101,66 @@ implements ClassVisitor, // Implementations for ConstantVisitor. - public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) { - classConstant.u2nameIndex = - remapConstantIndex(classConstant.u2nameIndex); + // Nothing to do. } - public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) + public void visitLongConstant(Clazz clazz, LongConstant longConstant) { // Nothing to do. } - public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) + public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) { - fieldrefConstant.u2classIndex = - remapConstantIndex(fieldrefConstant.u2classIndex); - fieldrefConstant.u2nameAndTypeIndex = - remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex); + // Nothing to do. } - public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) + public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) { // Nothing to do. } - public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + stringConstant.u2stringIndex = + remapConstantIndex(stringConstant.u2stringIndex); + } + + + public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) { // Nothing to do. } + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + invokeDynamicConstant.u2nameAndTypeIndex = + remapConstantIndex(invokeDynamicConstant.u2nameAndTypeIndex); + } + + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + methodHandleConstant.u2referenceIndex = + remapConstantIndex(methodHandleConstant.u2referenceIndex); + } + + + public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) + { + fieldrefConstant.u2classIndex = + remapConstantIndex(fieldrefConstant.u2classIndex); + fieldrefConstant.u2nameAndTypeIndex = + remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex); + } + + public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) { interfaceMethodrefConstant.u2classIndex = @@ -143,12 +170,6 @@ implements ClassVisitor, } - public void visitLongConstant(Clazz clazz, LongConstant longConstant) - { - // Nothing to do. - } - - public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) { methodrefConstant.u2classIndex = @@ -158,25 +179,26 @@ implements ClassVisitor, } - public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { - nameAndTypeConstant.u2nameIndex = - remapConstantIndex(nameAndTypeConstant.u2nameIndex); - nameAndTypeConstant.u2descriptorIndex = - remapConstantIndex(nameAndTypeConstant.u2descriptorIndex); + classConstant.u2nameIndex = + remapConstantIndex(classConstant.u2nameIndex); } - public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) { - stringConstant.u2stringIndex = - remapConstantIndex(stringConstant.u2stringIndex); + methodTypeConstant.u2descriptorIndex = + remapConstantIndex(methodTypeConstant.u2descriptorIndex); } - public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) { - // Nothing to do. + nameAndTypeConstant.u2nameIndex = + remapConstantIndex(nameAndTypeConstant.u2nameIndex); + nameAndTypeConstant.u2descriptorIndex = + remapConstantIndex(nameAndTypeConstant.u2descriptorIndex); } @@ -230,6 +252,16 @@ implements ClassVisitor, } + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + bootstrapMethodsAttribute.u2attributeNameIndex = + remapConstantIndex(bootstrapMethodsAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the bootstrap method entries. + bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); + } + + public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) { sourceFileAttribute.u2attributeNameIndex = @@ -410,6 +442,19 @@ implements ClassVisitor, } + // Implementations for BootstrapMethodInfoVisitor. + + public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) + { + bootstrapMethodInfo.u2methodHandleIndex = + remapConstantIndex(bootstrapMethodInfo.u2methodHandleIndex); + + // Remap the constant pool references of the bootstrap methods.. + remapConstantIndexArray(bootstrapMethodInfo.u2methodArguments, + bootstrapMethodInfo.u2methodArgumentCount); + } + + // Implementations for InnerClassesInfoVisitor. public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) diff --git a/src/proguard/classfile/editor/ConstantPoolShrinker.java b/src/proguard/classfile/editor/ConstantPoolShrinker.java new file mode 100644 index 0000000..8c8e5d6 --- /dev/null +++ b/src/proguard/classfile/editor/ConstantPoolShrinker.java @@ -0,0 +1,578 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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.classfile.editor; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.annotation.*; +import proguard.classfile.attribute.annotation.visitor.*; +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.instruction.*; +import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; + +import java.util.Arrays; + +/** + * This ClassVisitor removes all unused entries from the constant pool. + * + * @author Eric Lafortune + */ +public class ConstantPoolShrinker +extends SimplifiedVisitor +implements ClassVisitor, + MemberVisitor, + ConstantVisitor, + AttributeVisitor, + BootstrapMethodInfoVisitor, + InnerClassesInfoVisitor, + ExceptionInfoVisitor, + StackMapFrameVisitor, + VerificationTypeVisitor, + LocalVariableInfoVisitor, + LocalVariableTypeInfoVisitor, + AnnotationVisitor, + ElementValueVisitor, + InstructionVisitor +{ + // A visitor info flag to indicate the constant is being used. + private static final Object USED = new Object(); + + private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; + private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + // Mark this class's name. + markConstant(programClass, programClass.u2thisClass); + + // Mark the superclass class constant. + programClass.superClassConstantAccept(this); + + // Mark the interface class constants. + programClass.interfaceConstantsAccept(this); + + // Mark the constants referenced by the class members. + programClass.fieldsAccept(this); + programClass.methodsAccept(this); + + // Mark the attributes. + programClass.attributesAccept(this); + + // Shift the used constant pool entries together, filling out the + // index map. + int newConstantPoolCount = + shrinkConstantPool(programClass.constantPool, + programClass.u2constantPoolCount); + + // 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); + } + } + + + // Implementations for MemberVisitor. + + public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) + { + // Mark the name and descriptor. + markConstant(programClass, programMember.u2nameIndex); + markConstant(programClass, programMember.u2descriptorIndex); + + // Mark the attributes. + programMember.attributesAccept(programClass, this); + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) + { + markAsUsed(constant); + } + + + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + markAsUsed(stringConstant); + + markConstant(clazz, stringConstant.u2stringIndex); + } + + + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + markAsUsed(invokeDynamicConstant); + + markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); + + // Mark the bootstrap methods attribute. + clazz.attributesAccept(this); + } + + + public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) + { + markAsUsed(methodHandleConstant); + + markConstant(clazz, methodHandleConstant.u2referenceIndex); + } + + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) + { + markAsUsed(refConstant); + + markConstant(clazz, refConstant.u2classIndex); + markConstant(clazz, refConstant.u2nameAndTypeIndex); + } + + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + markAsUsed(classConstant); + + markConstant(clazz, classConstant.u2nameIndex); + } + + + public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) + { + markAsUsed(methodTypeConstant); + + markConstant(clazz, methodTypeConstant.u2descriptorIndex); + } + + + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) + { + markAsUsed(nameAndTypeConstant); + + markConstant(clazz, nameAndTypeConstant.u2nameIndex); + markConstant(clazz, nameAndTypeConstant.u2descriptorIndex); + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) + { + markConstant(clazz, attribute.u2attributeNameIndex); + } + + + public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) + { + markConstant(clazz, bootstrapMethodsAttribute.u2attributeNameIndex); + + // Mark the bootstrap method entries. + bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); + } + + + public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) + { + markConstant(clazz, sourceFileAttribute.u2attributeNameIndex); + markConstant(clazz, sourceFileAttribute.u2sourceFileIndex); + } + + + public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) + { + markConstant(clazz, sourceDirAttribute.u2attributeNameIndex); + markConstant(clazz, sourceDirAttribute.u2sourceDirIndex); + } + + + public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) + { + markConstant(clazz, innerClassesAttribute.u2attributeNameIndex); + + // Mark the outer class entries. + innerClassesAttribute.innerClassEntriesAccept(clazz, this); + } + + + public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) + { + markConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex); + markConstant(clazz, enclosingMethodAttribute.u2classIndex); + + if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) + { + markConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex); + } + } + + + public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) + { + markConstant(clazz, signatureAttribute.u2attributeNameIndex); + markConstant(clazz, signatureAttribute.u2signatureIndex); + } + + + public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) + { + markConstant(clazz, constantValueAttribute.u2attributeNameIndex); + markConstant(clazz, constantValueAttribute.u2constantValueIndex); + } + + + public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) + { + markConstant(clazz, exceptionsAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the exceptions. + exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this); + } + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + markConstant(clazz, codeAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the instructions, + // by the exceptions, and by the attributes. + codeAttribute.instructionsAccept(clazz, method, this); + codeAttribute.exceptionsAccept(clazz, method, this); + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) + { + markConstant(clazz, stackMapAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the stack map frames. + stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); + } + + + public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) + { + markConstant(clazz, stackMapTableAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the stack map frames. + stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); + } + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute 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) + { + markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the local variable types. + localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + } + + + public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) + { + markConstant(clazz, annotationsAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the annotations. + annotationsAttribute.annotationsAccept(clazz, this); + } + + + public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) + { + markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the annotations. + parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); + } + + + public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) + { + markConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex); + + // Mark the constant pool entries referenced by the element value. + annotationDefaultAttribute.defaultValueAccept(clazz, this); + } + + + // Implementations for BootstrapMethodInfoVisitor. + + public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) + { + markConstant(clazz, bootstrapMethodInfo.u2methodHandleIndex); + + // Mark the constant pool entries referenced by the arguments. + bootstrapMethodInfo.methodArgumentsAccept(clazz, this); + } + + + // Implementations for InnerClassesInfoVisitor. + + public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) + { + innerClassesInfo.innerClassConstantAccept(clazz, this); + innerClassesInfo.outerClassConstantAccept(clazz, this); + innerClassesInfo.innerNameConstantAccept(clazz, this); + } + + + // Implementations for ExceptionInfoVisitor. + + public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) + { + if (exceptionInfo.u2catchType != 0) + { + markConstant(clazz, exceptionInfo.u2catchType); + } + } + + + // Implementations for StackMapFrameVisitor. + + public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {} + + + public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) + { + // Mark the constant pool entries referenced by the verification types. + sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); + } + + + public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) + { + // Mark the constant pool entries referenced by the verification types. + moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); + } + + + public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) + { + // Mark the constant pool entries referenced by the verification types. + fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); + fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); + } + + + // Implementations for VerificationTypeVisitor. + + public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} + + + public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) + { + markConstant(clazz, objectType.u2classIndex); + } + + + // Implementations for LocalVariableInfoVisitor. + + public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) + { + markConstant(clazz, localVariableInfo.u2nameIndex); + markConstant(clazz, localVariableInfo.u2descriptorIndex); + } + + + // Implementations for LocalVariableTypeInfoVisitor. + + public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) + { + markConstant(clazz, localVariableTypeInfo.u2nameIndex); + markConstant(clazz, localVariableTypeInfo.u2signatureIndex); + } + + + // Implementations for AnnotationVisitor. + + public void visitAnnotation(Clazz clazz, Annotation annotation) + { + markConstant(clazz, annotation.u2typeIndex); + + // Mark the constant pool entries referenced by the element values. + annotation.elementValuesAccept(clazz, this); + } + + + // Implementations for ElementValueVisitor. + + public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) + { + if (constantElementValue.u2elementNameIndex != 0) + { + markConstant(clazz, constantElementValue.u2elementNameIndex); + } + + markConstant(clazz, constantElementValue.u2constantValueIndex); + } + + + public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) + { + if (enumConstantElementValue.u2elementNameIndex != 0) + { + markConstant(clazz, enumConstantElementValue.u2elementNameIndex); + } + + markConstant(clazz, enumConstantElementValue.u2typeNameIndex); + markConstant(clazz, enumConstantElementValue.u2constantNameIndex); + } + + + public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) + { + if (classElementValue.u2elementNameIndex != 0) + { + markConstant(clazz, classElementValue.u2elementNameIndex); + } + + markConstant(clazz, classElementValue.u2classInfoIndex); + } + + + public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) + { + if (annotationElementValue.u2elementNameIndex != 0) + { + markConstant(clazz, annotationElementValue.u2elementNameIndex); + } + + // Mark the constant pool entries referenced by the annotation. + annotationElementValue.annotationAccept(clazz, this); + } + + + public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) + { + if (arrayElementValue.u2elementNameIndex != 0) + { + markConstant(clazz, arrayElementValue.u2elementNameIndex); + } + + // Mark the constant pool entries referenced by the element values. + arrayElementValue.elementValuesAccept(clazz, annotation, this); + } + + + // Implementations for InstructionVisitor. + + public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} + + + public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) + { + markConstant(clazz, constantInstruction.constantIndex); + } + + + // Small utility methods. + + /** + * Marks the given constant pool entry of the given class. This includes + * visiting any referenced objects. + */ + private void markConstant(Clazz clazz, int index) + { + clazz.constantPoolEntryAccept(index, this); + } + + + /** + * Marks the given visitor accepter as being used. + */ + private void markAsUsed(Constant constant) + { + constant.setVisitorInfo(USED); + } + + + /** + * Returns whether the given visitor accepter has been marked as being used. + */ + private boolean isUsed(VisitorAccepter visitorAccepter) + { + return visitorAccepter.getVisitorInfo() == USED; + } + + + /** + * Removes all constants that are not marked as being used from the given + * constant pool. + * @return the new number of entries. + */ + private int shrinkConstantPool(Constant[] constantPool, int length) + { + // Create a new index map, if necessary. + 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]; + + // Don't update the flag if this is the second half of a long entry. + if (constant != null) + { + isUsed = isUsed(constant); + } + + if (isUsed) + { + constantPool[counter++] = constant; + } + } + + // Clear the remaining constant pool elements. + Arrays.fill(constantPool, counter, length, null); + + return counter; + } +} diff --git a/src/proguard/classfile/editor/ConstantPoolSorter.java b/src/proguard/classfile/editor/ConstantPoolSorter.java index faae318..8e18865 100644 --- a/src/proguard/classfile/editor/ConstantPoolSorter.java +++ b/src/proguard/classfile/editor/ConstantPoolSorter.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-2011 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 @@ -112,10 +112,7 @@ implements ClassVisitor System.arraycopy(newConstantPool, 0, programClass.constantPool, 0, newLength); // Clear any remaining entries. - for (int index = newLength; index < constantPoolCount; index++) - { - programClass.constantPool[index] = null; - } + Arrays.fill(programClass.constantPool, newLength, constantPoolCount, null); programClass.u2constantPoolCount = newLength; diff --git a/src/proguard/classfile/editor/ElementValueAdder.java b/src/proguard/classfile/editor/ElementValueAdder.java index 8cbd11d..895fd68 100644 --- a/src/proguard/classfile/editor/ElementValueAdder.java +++ b/src/proguard/classfile/editor/ElementValueAdder.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-2011 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/classfile/editor/ElementValuesEditor.java b/src/proguard/classfile/editor/ElementValuesEditor.java index bfc4e9f..ce9352a 100644 --- a/src/proguard/classfile/editor/ElementValuesEditor.java +++ b/src/proguard/classfile/editor/ElementValuesEditor.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-2011 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/classfile/editor/ExceptionAdder.java b/src/proguard/classfile/editor/ExceptionAdder.java index 1ccb1a6..ee0fb52 100644 --- a/src/proguard/classfile/editor/ExceptionAdder.java +++ b/src/proguard/classfile/editor/ExceptionAdder.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-2011 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/classfile/editor/ExceptionInfoAdder.java b/src/proguard/classfile/editor/ExceptionInfoAdder.java index e0cc9c5..5fd98a8 100644 --- a/src/proguard/classfile/editor/ExceptionInfoAdder.java +++ b/src/proguard/classfile/editor/ExceptionInfoAdder.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-2011 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/classfile/editor/ExceptionsAttributeEditor.java b/src/proguard/classfile/editor/ExceptionsAttributeEditor.java index 4509a9a..d49658a 100644 --- a/src/proguard/classfile/editor/ExceptionsAttributeEditor.java +++ b/src/proguard/classfile/editor/ExceptionsAttributeEditor.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-2011 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/classfile/editor/InnerClassesAccessFixer.java b/src/proguard/classfile/editor/InnerClassesAccessFixer.java new file mode 100644 index 0000000..1d991df --- /dev/null +++ b/src/proguard/classfile/editor/InnerClassesAccessFixer.java @@ -0,0 +1,83 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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.classfile.editor; + +import proguard.classfile.*; +import proguard.classfile.attribute.visitor.InnerClassesInfoVisitor; +import proguard.classfile.attribute.InnerClassesInfo; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.util.*; +import proguard.classfile.visitor.*; + +/** + * This InnerClassesInfoVisitor fixes the inner class access flags of the + * inner classes information that it visits. + * + * @author Eric Lafortune + */ +public class InnerClassesAccessFixer +extends SimplifiedVisitor +implements InnerClassesInfoVisitor, + ConstantVisitor, + ClassVisitor +{ + private int innerClassAccessFlags; + + + // Implementations for InnerClassesInfoVisitor. + + public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) + { + // The current access flags are the default. + innerClassAccessFlags = innerClassesInfo.u2innerClassAccessFlags; + + // See if we can find new access flags. + innerClassesInfo.innerClassConstantAccept(clazz, this); + + // Update the access flags. + innerClassesInfo.u2innerClassAccessFlags = innerClassAccessFlags; + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + classConstant.referencedClassAccept(this); + } + + + // Implementations for ClassVisitor. + + public void visitLibraryClass(LibraryClass libraryClass) {} + + + public void visitProgramClass(ProgramClass programClass) + { + innerClassAccessFlags = + AccessUtil.replaceAccessFlags(innerClassAccessFlags, + programClass.u2accessFlags); + } +}
\ No newline at end of file diff --git a/src/proguard/classfile/editor/InstructionAdder.java b/src/proguard/classfile/editor/InstructionAdder.java index 60fde6d..34fb63b 100644 --- a/src/proguard/classfile/editor/InstructionAdder.java +++ b/src/proguard/classfile/editor/InstructionAdder.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-2011 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/classfile/editor/InstructionWriter.java b/src/proguard/classfile/editor/InstructionWriter.java index d842358..b7da62f 100644 --- a/src/proguard/classfile/editor/InstructionWriter.java +++ b/src/proguard/classfile/editor/InstructionWriter.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-2011 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/classfile/editor/InterfaceAdder.java b/src/proguard/classfile/editor/InterfaceAdder.java index e095af6..9c11d97 100644 --- a/src/proguard/classfile/editor/InterfaceAdder.java +++ b/src/proguard/classfile/editor/InterfaceAdder.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-2011 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/classfile/editor/InterfaceSorter.java b/src/proguard/classfile/editor/InterfaceSorter.java index 6521369..176e13e 100644 --- a/src/proguard/classfile/editor/InterfaceSorter.java +++ b/src/proguard/classfile/editor/InterfaceSorter.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-2011 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,10 +21,14 @@ package proguard.classfile.editor; import proguard.classfile.*; -import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.util.*; import proguard.classfile.visitor.ClassVisitor; -import java.util.Arrays; +import java.util.*; /** * This ClassVisitor sorts the interfaces of the program classes that it visits. @@ -33,7 +37,8 @@ import java.util.Arrays; */ public class InterfaceSorter extends SimplifiedVisitor -implements ClassVisitor +implements ClassVisitor, + AttributeVisitor { // Implementations for ClassVisitor. @@ -42,26 +47,106 @@ implements ClassVisitor int[] interfaces = programClass.u2interfaces; int interfacesCount = programClass.u2interfacesCount; - // Sort the interfaces. - Arrays.sort(interfaces, 0, interfacesCount); + if (interfacesCount > 1) + { + // Sort the interfaces. + Arrays.sort(interfaces, 0, interfacesCount); + + // Remove any duplicate entries. + int newInterfacesCount = 0; + int previousInterfaceIndex = 0; + for (int index = 0; index < interfacesCount; index++) + { + int interfaceIndex = interfaces[index]; + + // Isn't this a duplicate of the previous interface? + if (interfaceIndex != previousInterfaceIndex) + { + interfaces[newInterfacesCount++] = interfaceIndex; + + // Remember the interface. + previousInterfaceIndex = interfaceIndex; + } + } + + programClass.u2interfacesCount = newInterfacesCount; + + // Update the signature, if any + programClass.attributesAccept(this); + } + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) + { + // Process the generic definitions, superclass, and implemented + // interfaces. + String signature = clazz.getString(signatureAttribute.u2signatureIndex); + + // Count the signature types. + InternalTypeEnumeration internalTypeEnumeration = + new InternalTypeEnumeration(signature); - // Remove any duplicate entries. - int newInterfacesCount = 0; - int previousInterfaceIndex = 0; - for (int index = 0; index < interfacesCount; index++) + int count = 0; + int interfacesCount = -1; + while (internalTypeEnumeration.hasMoreTypes()) { - int interfaceIndex = interfaces[index]; + String internalType = internalTypeEnumeration.nextType(); - // Isn't this a duplicate of the previous interface? - if (interfaceIndex != previousInterfaceIndex) + count++; + + if (ClassUtil.isInternalClassType(internalType)) { - interfaces[newInterfacesCount++] = interfaceIndex; + interfacesCount++; + } + } + + // Put the signature types in an array. + internalTypeEnumeration = + new InternalTypeEnumeration(signature); + + String[] internalTypes = new String[count]; + + for (int index = 0; index < count; index++) + { + String internalType = internalTypeEnumeration.nextType(); + + internalTypes[index] = internalType; + } - // Remember the interface. - previousInterfaceIndex = interfaceIndex; + // Sort the interface types in the array. + Arrays.sort(internalTypes, count - interfacesCount, count); + + // Recompose the signature types in a string. + StringBuffer newSignatureBuffer = new StringBuffer(); + + for (int index = 0; index < count; index++) + { + // Is this not an interface type, or an interface type that isn't + // a duplicate of the previous interface type? + if (index < count - interfacesCount || + !internalTypes[index].equals(internalTypes[index-1])) + { + newSignatureBuffer.append(internalTypes[index]); } } - programClass.u2interfacesCount = newInterfacesCount; + String newSignature = newSignatureBuffer.toString(); + + // Did the signature change? + if (!newSignature.equals(signature)) + { + // Update the signature. + ((Utf8Constant)((ProgramClass)clazz).constantPool[signatureAttribute.u2signatureIndex]).setString(newSignatureBuffer.toString()); + + // Clear the referenced classes. + // TODO: Properly update the referenced classes. + signatureAttribute.referencedClasses = null; + } } } diff --git a/src/proguard/classfile/editor/InterfacesEditor.java b/src/proguard/classfile/editor/InterfacesEditor.java index d3170e1..59cdd6a 100644 --- a/src/proguard/classfile/editor/InterfacesEditor.java +++ b/src/proguard/classfile/editor/InterfacesEditor.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-2011 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/classfile/editor/LineNumberInfoAdder.java b/src/proguard/classfile/editor/LineNumberInfoAdder.java index aa8c0c4..b0db7fb 100644 --- a/src/proguard/classfile/editor/LineNumberInfoAdder.java +++ b/src/proguard/classfile/editor/LineNumberInfoAdder.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-2011 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/classfile/editor/LineNumberTableAttributeEditor.java b/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java index ab96b38..7497458 100644 --- a/src/proguard/classfile/editor/LineNumberTableAttributeEditor.java +++ b/src/proguard/classfile/editor/LineNumberTableAttributeEditor.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-2011 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/classfile/editor/LocalVariableInfoAdder.java b/src/proguard/classfile/editor/LocalVariableInfoAdder.java index f285e4f..0f47933 100644 --- a/src/proguard/classfile/editor/LocalVariableInfoAdder.java +++ b/src/proguard/classfile/editor/LocalVariableInfoAdder.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-2011 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/classfile/editor/LocalVariableTableAttributeEditor.java b/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java index 053b628..8bb051d 100644 --- a/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.java +++ b/src/proguard/classfile/editor/LocalVariableTableAttributeEditor.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-2011 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/classfile/editor/LocalVariableTypeInfoAdder.java b/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java index ca50f3f..a1c1379 100644 --- a/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.java +++ b/src/proguard/classfile/editor/LocalVariableTypeInfoAdder.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-2011 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/classfile/editor/LocalVariableTypeTableAttributeEditor.java b/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java index fe5a64d..9b1ebd5 100644 --- a/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.java +++ b/src/proguard/classfile/editor/LocalVariableTypeTableAttributeEditor.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-2011 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/classfile/editor/MemberAdder.java b/src/proguard/classfile/editor/MemberAdder.java index 5f939bb..7791e3b 100644 --- a/src/proguard/classfile/editor/MemberAdder.java +++ b/src/proguard/classfile/editor/MemberAdder.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-2011 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 @@ -26,8 +26,9 @@ import proguard.classfile.util.SimplifiedVisitor; import proguard.classfile.visitor.MemberVisitor; /** - * This ConstantVisitor adds all class members that it visits to the given - * target class. + * This MemberVisitor copies all class members that it visits to the given + * target class. Their visitor info is set to the class members from which they + * were copied. * * @author Eric Lafortune */ @@ -45,8 +46,9 @@ implements MemberVisitor private static final Attribute[] EMPTY_ATTRIBUTES = new Attribute[0]; - private final ProgramClass targetClass; -// private final boolean addFields; + private final ProgramClass targetClass; +// private final boolean addFields; + private final MemberVisitor extraMemberVisitor; private final ConstantAdder constantAdder; private final ClassEditor classEditor; @@ -59,13 +61,30 @@ implements MemberVisitor * @param targetClass the class to which all visited class members will be * added. */ + public MemberAdder(ProgramClass targetClass) + { + this(targetClass, null); + } + + + /** + * Creates a new MemberAdder that will copy methods into the given target + * class. + * @param targetClass the class to which all visited class members + * will be added. + * @param extraMemberVisitor an optional member visitor that visits each + * new member right after it has been added. This + * allows changing the visitor info, for instance. + */ // * @param addFields specifies whether fields should be added, or fused // * with the present fields. - public MemberAdder(ProgramClass targetClass)//), -// boolean addFields) + public MemberAdder(ProgramClass targetClass, +// boolean addFields, + MemberVisitor extraMemberVisitor) { - this.targetClass = targetClass; -// this.addFields = addFields; + this.targetClass = targetClass; +// this.addFields = addFields; + this.extraMemberVisitor = extraMemberVisitor; constantAdder = new ConstantAdder(targetClass); classEditor = new ClassEditor(targetClass); @@ -150,6 +169,12 @@ implements MemberVisitor // Add the completed field. classEditor.addField(newProgramField); + + // Visit the newly added field, if necessary. + if (extraMemberVisitor != null) + { + extraMemberVisitor.visitProgramField(targetClass, newProgramField); + } } @@ -240,6 +265,12 @@ implements MemberVisitor // Add the completed method. classEditor.addMethod(newProgramMethod); + + // Visit the newly added method, if necessary. + if (extraMemberVisitor != null) + { + extraMemberVisitor.visitProgramMethod(targetClass, newProgramMethod); + } } diff --git a/src/proguard/classfile/editor/MemberReferenceFixer.java b/src/proguard/classfile/editor/MemberReferenceFixer.java index 4bd8af5..6d665c1 100644 --- a/src/proguard/classfile/editor/MemberReferenceFixer.java +++ b/src/proguard/classfile/editor/MemberReferenceFixer.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-2011 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 @@ -298,22 +298,17 @@ implements ClassVisitor, { Clazz referencedClass = enclosingMethodAttribute.referencedClass; - // Does it have a new class? - if (!enclosingMethodAttribute.getClassName(clazz).equals(referencedClass.getName())) - { - // Update the class index. - enclosingMethodAttribute.u2classIndex = - new ConstantPoolEditor((ProgramClass)clazz).addClassConstant(referencedClass); - } - // Does it have a new name or type? - if (!enclosingMethodAttribute.getName(clazz).equals(referencedMember.getName(referencedClass)) || - !enclosingMethodAttribute.getType(clazz).equals(referencedMember.getDescriptor(referencedClass))) + String newName = referencedMember.getName(referencedClass); + String newType = referencedMember.getDescriptor(referencedClass); + + if (!enclosingMethodAttribute.getName(clazz).equals(newName) || + !enclosingMethodAttribute.getType(clazz).equals(newType)) { // Update the name and type index. enclosingMethodAttribute.u2nameAndTypeIndex = - new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(referencedMember.getName(referencedClass), - referencedMember.getDescriptor(referencedClass)); + new ConstantPoolEditor((ProgramClass)clazz).addNameAndTypeConstant(newName, + newType); } } } @@ -433,10 +428,9 @@ implements ClassVisitor, Member referencedMember) { System.out.println("MemberReferenceFixer:"); - System.out.println(" Class file = "+clazz.getName()); - System.out.println(" Ref class = "+referencedClass.getName()); - System.out.println(" Ref member name = "+stringConstant.getString(clazz)); - System.out.println(" -> "+referencedMember.getName(referencedClass)); + System.out.println(" ["+clazz.getName()+"]: String ["+ + stringConstant.getString(clazz)+"] -> ["+ + referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]"); } @@ -446,11 +440,8 @@ implements ClassVisitor, Member referencedMember) { System.out.println("MemberReferenceFixer:"); - System.out.println(" Class file = "+clazz.getName()); - System.out.println(" Ref class = "+referencedClass.getName()); - System.out.println(" Ref member name = "+refConstant.getName(clazz)); - System.out.println(" -> "+referencedMember.getName(referencedClass)); - System.out.println(" Ref descriptor = "+refConstant.getType(clazz)); - System.out.println(" -> "+referencedMember.getDescriptor(referencedClass)); + System.out.println(" ["+clazz.getName()+"]: ["+ + refConstant.getClassName(clazz)+"."+refConstant.getName(clazz)+" "+refConstant.getType(clazz)+"] -> ["+ + referencedClass.getName()+"."+referencedMember.getName(referencedClass)+" "+referencedMember.getDescriptor(referencedClass)+"]"); } } diff --git a/src/proguard/classfile/editor/MethodInvocationFixer.java b/src/proguard/classfile/editor/MethodInvocationFixer.java index ef76012..f33ef1d 100644 --- a/src/proguard/classfile/editor/MethodInvocationFixer.java +++ b/src/proguard/classfile/editor/MethodInvocationFixer.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-2011 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 @@ -28,7 +28,6 @@ import proguard.classfile.constant.visitor.ConstantVisitor; import proguard.classfile.instruction.*; import proguard.classfile.instruction.visitor.InstructionVisitor; import proguard.classfile.util.*; -import proguard.classfile.visitor.*; /** * This AttributeVisitor fixes all inappropriate special/virtual/static/interface @@ -40,9 +39,7 @@ public class MethodInvocationFixer extends SimplifiedVisitor implements AttributeVisitor, InstructionVisitor, - ConstantVisitor, - ClassVisitor, - MemberVisitor + ConstantVisitor { private static final boolean DEBUG = false; @@ -88,7 +85,8 @@ implements AttributeVisitor, clazz.constantPoolEntryAccept(constantIndex, this); // Did we find the called class and method? - if (referencedMethod != null) + if (referencedClass != null && + referencedMethod != null) { // Do we need to update the opcode? byte opcode = constantInstruction.opcode; @@ -168,6 +166,7 @@ implements AttributeVisitor, // but not a super call)? if (opcode != InstructionConstants.OP_INVOKEVIRTUAL && (opcode != InstructionConstants.OP_INVOKESPECIAL || + clazz.equals(referencedClass) || !clazz.extends_(referencedClass))) { // Replace the invocation by an invokevirtual instruction. @@ -194,40 +193,30 @@ implements AttributeVisitor, public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) { - // Check if this is an interface method. Note that we're interested in - // the class of the method reference, not in the class in which the - // method was actually found. - //refConstant.referencedClassAccept(this); - clazz.constantPoolEntryAccept(refConstant.u2classIndex, this); - - // Get the referenced access flags and names. - refConstant.referencedMemberAccept(this); - } - + // Remember the referenced class. Note that we're interested in the + // class of the method reference, not in the class in which the + // method was actually found, unless it is an array type. + // + if (ClassUtil.isInternalArrayType(refConstant.getClassName(clazz))) + { + // For an array type, the class will be java.lang.Object. + referencedClass = refConstant.referencedClass; + } + else + { + clazz.constantPoolEntryAccept(refConstant.u2classIndex, this); + } - public void visitClassConstant(Clazz clazz, ClassConstant classConstant) - { - // Check if this is an interface class. - classConstant.referencedClassAccept(this); + // Remember the referenced method. + referencedMethodClass = refConstant.referencedClass; + referencedMethod = refConstant.referencedMember; } - // Implementations for ClassVisitor. - - public void visitAnyClass(Clazz clazz) + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) { // Remember the referenced class. - referencedClass = clazz; - } - - - // Implementations for MemberVisitor. - - public void visitAnyMember(Clazz clazz, Member member) - { - // Remember the referenced method. - referencedMethodClass = clazz; - referencedMethod = member; + referencedClass = classConstant.referencedClass; } diff --git a/src/proguard/classfile/editor/NameAndTypeShrinker.java b/src/proguard/classfile/editor/NameAndTypeShrinker.java new file mode 100644 index 0000000..f316884 --- /dev/null +++ b/src/proguard/classfile/editor/NameAndTypeShrinker.java @@ -0,0 +1,188 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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.classfile.editor; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.editor.ConstantPoolRemapper; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.ClassVisitor; + +import java.util.Arrays; + + +/** + * This ClassVisitor removes NameAndType constant pool entries that are not + * used. + * + * @author Eric Lafortune + */ +public class NameAndTypeShrinker +extends SimplifiedVisitor +implements ClassVisitor, + ConstantVisitor, + AttributeVisitor +{ + // A visitor info flag to indicate the NameAndType constant pool entry is being used. + private static final Object USED = new Object(); + + private int[] constantIndexMap; + private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + // Mark the NameAndType entries referenced by all other constant pool + // entries. + programClass.constantPoolEntriesAccept(this); + + // Mark the NameAndType entries referenced by all EnclosingMethod + // attributes. + programClass.attributesAccept(this); + + // Shift the used constant pool entries together, filling out the + // index map. + int newConstantPoolCount = + shrinkConstantPool(programClass.constantPool, + programClass.u2constantPoolCount); + + // 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); + } + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) + { + markNameAndTypeConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); + } + + + public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) + { + markNameAndTypeConstant(clazz, refConstant.u2nameAndTypeIndex); + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) + { + if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) + { + markNameAndTypeConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex); + } + } + + + // Small utility methods. + + /** + * Marks the given UTF-8 constant pool entry of the given class. + */ + private void markNameAndTypeConstant(Clazz clazz, int index) + { + markAsUsed((NameAndTypeConstant)((ProgramClass)clazz).getConstant(index)); + } + + + /** + * Marks the given VisitorAccepter as being used. + * In this context, the VisitorAccepter will be a NameAndTypeConstant object. + */ + private void markAsUsed(VisitorAccepter visitorAccepter) + { + visitorAccepter.setVisitorInfo(USED); + } + + + /** + * Returns whether the given VisitorAccepter has been marked as being used. + * In this context, the VisitorAccepter will be a NameAndTypeConstant object. + */ + private boolean isUsed(VisitorAccepter visitorAccepter) + { + return visitorAccepter.getVisitorInfo() == USED; + } + + + /** + * Removes all NameAndType entries that are not marked as being used + * from the given constant pool. + * @return the new number of entries. + */ + private int shrinkConstantPool(Constant[] constantPool, int length) + { + // Create a new index map, if necessary. + if (constantIndexMap == null || + 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]; + + // Don't update the flag if this is the second half of a long entry. + if (constant != null) + { + isUsed = constant.getTag() != ClassConstants.CONSTANT_NameAndType || + isUsed(constant); + } + + if (isUsed) + { + constantPool[counter++] = constant; + } + } + + // Clear the remaining constant pool elements. + Arrays.fill(constantPool, counter, length, null); + + return counter; + } +} diff --git a/src/proguard/classfile/editor/NamedAttributeDeleter.java b/src/proguard/classfile/editor/NamedAttributeDeleter.java index 0c4d339..5ae950d 100644 --- a/src/proguard/classfile/editor/NamedAttributeDeleter.java +++ b/src/proguard/classfile/editor/NamedAttributeDeleter.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-2011 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/classfile/editor/ParameterAnnotationsAttributeEditor.java b/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java index 4cad6b8..c97e2c8 100644 --- a/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.java +++ b/src/proguard/classfile/editor/ParameterAnnotationsAttributeEditor.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-2011 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/classfile/editor/StackSizeUpdater.java b/src/proguard/classfile/editor/StackSizeUpdater.java index 94e0519..cc743b1 100644 --- a/src/proguard/classfile/editor/StackSizeUpdater.java +++ b/src/proguard/classfile/editor/StackSizeUpdater.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-2011 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/classfile/editor/SubclassAdder.java b/src/proguard/classfile/editor/SubclassAdder.java index 6b9fd64..f944ef8 100644 --- a/src/proguard/classfile/editor/SubclassAdder.java +++ b/src/proguard/classfile/editor/SubclassAdder.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-2011 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/classfile/editor/SubclassToAdder.java b/src/proguard/classfile/editor/SubclassToAdder.java index deb242f..f4cdd70 100644 --- a/src/proguard/classfile/editor/SubclassToAdder.java +++ b/src/proguard/classfile/editor/SubclassToAdder.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-2011 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/classfile/editor/Utf8Shrinker.java b/src/proguard/classfile/editor/Utf8Shrinker.java new file mode 100644 index 0000000..b9dac44 --- /dev/null +++ b/src/proguard/classfile/editor/Utf8Shrinker.java @@ -0,0 +1,455 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2011 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.classfile.editor; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.annotation.*; +import proguard.classfile.attribute.annotation.visitor.*; +import proguard.classfile.attribute.preverification.*; +import proguard.classfile.attribute.visitor.*; +import proguard.classfile.constant.*; +import proguard.classfile.constant.visitor.ConstantVisitor; +import proguard.classfile.editor.ConstantPoolRemapper; +import proguard.classfile.util.SimplifiedVisitor; +import proguard.classfile.visitor.*; + +import java.util.Arrays; + + +/** + * This ClassVisitor removes UTF-8 constant pool entries that are not used. + * + * @author Eric Lafortune + */ +public class Utf8Shrinker +extends SimplifiedVisitor +implements ClassVisitor, + MemberVisitor, + ConstantVisitor, + AttributeVisitor, + InnerClassesInfoVisitor, + LocalVariableInfoVisitor, + LocalVariableTypeInfoVisitor, + AnnotationVisitor, + ElementValueVisitor +{ + // A visitor info flag to indicate the UTF-8 constant pool entry is being used. + private static final Object USED = new Object(); + + private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; + private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + // Mark the UTF-8 entries referenced by the other constant pool entries. + programClass.constantPoolEntriesAccept(this); + + // Mark the UTF-8 entries referenced by the fields and methods. + programClass.fieldsAccept(this); + programClass.methodsAccept(this); + + // Mark the UTF-8 entries referenced by the attributes. + programClass.attributesAccept(this); + + // Shift the used constant pool entries together, filling out the + // index map. + int newConstantPoolCount = + shrinkConstantPool(programClass.constantPool, + programClass.u2constantPoolCount); + + // 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); + } + } + + + // Implementations for MemberVisitor. + + public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) + { + // Mark the name and descriptor UTF-8 entries. + markCpUtf8Entry(programClass, programMember.u2nameIndex); + markCpUtf8Entry(programClass, programMember.u2descriptorIndex); + + // Mark the UTF-8 entries referenced by the attributes. + programMember.attributesAccept(programClass, this); + } + + + // Implementations for ConstantVisitor. + + public void visitAnyConstant(Clazz clazz, Constant constant) {} + + + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + markCpUtf8Entry(clazz, stringConstant.u2stringIndex); + } + + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + markCpUtf8Entry(clazz, classConstant.u2nameIndex); + } + + + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) + { + markCpUtf8Entry(clazz, nameAndTypeConstant.u2nameIndex); + markCpUtf8Entry(clazz, nameAndTypeConstant.u2descriptorIndex); + } + + + // Implementations for AttributeVisitor. + + public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) + { + // This is the best we can do for unknown attributes. + markCpUtf8Entry(clazz, unknownAttribute.u2attributeNameIndex); + } + + + public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) + { + markCpUtf8Entry(clazz, sourceFileAttribute.u2attributeNameIndex); + + markCpUtf8Entry(clazz, sourceFileAttribute.u2sourceFileIndex); + } + + + public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) + { + markCpUtf8Entry(clazz, sourceDirAttribute.u2attributeNameIndex); + + markCpUtf8Entry(clazz, sourceDirAttribute.u2sourceDirIndex); + } + + + public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) + { + markCpUtf8Entry(clazz, innerClassesAttribute.u2attributeNameIndex); + + // Mark the UTF-8 entries referenced by the inner classes. + innerClassesAttribute.innerClassEntriesAccept(clazz, this); + } + + + public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) + { + markCpUtf8Entry(clazz, enclosingMethodAttribute.u2attributeNameIndex); + + // These entries have already been marked in the constant pool. + //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2classIndex); + //clazz.constantPoolEntryAccept(this, enclosingMethodAttribute.u2nameAndTypeIndex); + } + + + public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) + { + markCpUtf8Entry(clazz, deprecatedAttribute.u2attributeNameIndex); + } + + + public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) + { + markCpUtf8Entry(clazz, syntheticAttribute.u2attributeNameIndex); + } + + + public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) + { + markCpUtf8Entry(clazz, signatureAttribute.u2attributeNameIndex); + + markCpUtf8Entry(clazz, signatureAttribute.u2signatureIndex); + } + + + public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) + { + markCpUtf8Entry(clazz, constantValueAttribute.u2attributeNameIndex); + } + + + public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) + { + markCpUtf8Entry(clazz, exceptionsAttribute.u2attributeNameIndex); + } + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + markCpUtf8Entry(clazz, codeAttribute.u2attributeNameIndex); + + // Mark the UTF-8 entries referenced by the attributes. + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) + { + markCpUtf8Entry(clazz, stackMapAttribute.u2attributeNameIndex); + } + + + public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) + { + markCpUtf8Entry(clazz, stackMapTableAttribute.u2attributeNameIndex); + } + + + public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) + { + markCpUtf8Entry(clazz, lineNumberTableAttribute.u2attributeNameIndex); + } + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) + { + markCpUtf8Entry(clazz, localVariableTableAttribute.u2attributeNameIndex); + + // Mark the UTF-8 entries referenced by the local variables. + localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + } + + + public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) + { + markCpUtf8Entry(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); + + // Mark the UTF-8 entries referenced by the local variable types. + localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + } + + + public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) + { + markCpUtf8Entry(clazz, annotationsAttribute.u2attributeNameIndex); + + // Mark the UTF-8 entries referenced by the annotations. + annotationsAttribute.annotationsAccept(clazz, this); + } + + + public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) + { + markCpUtf8Entry(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); + + // Mark the UTF-8 entries referenced by the annotations. + parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); + } + + + public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) + { + markCpUtf8Entry(clazz, annotationDefaultAttribute.u2attributeNameIndex); + + // Mark the UTF-8 entries referenced by the element value. + annotationDefaultAttribute.defaultValueAccept(clazz, this); + } + + + // Implementations for InnerClassesInfoVisitor. + + public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) + { + if (innerClassesInfo.u2innerNameIndex != 0) + { + markCpUtf8Entry(clazz, innerClassesInfo.u2innerNameIndex); + } + } + + + // Implementations for LocalVariableInfoVisitor. + + public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) + { + markCpUtf8Entry(clazz, localVariableInfo.u2nameIndex); + markCpUtf8Entry(clazz, localVariableInfo.u2descriptorIndex); + } + + + // Implementations for LocalVariableTypeInfoVisitor. + + public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) + { + markCpUtf8Entry(clazz, localVariableTypeInfo.u2nameIndex); + markCpUtf8Entry(clazz, localVariableTypeInfo.u2signatureIndex); + } + + + // Implementations for AnnotationVisitor. + + public void visitAnnotation(Clazz clazz, Annotation annotation) + { + markCpUtf8Entry(clazz, annotation.u2typeIndex); + + // Mark the UTF-8 entries referenced by the element values. + annotation.elementValuesAccept(clazz, this); + } + + + // Implementations for ElementValueVisitor. + + public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) + { + if (constantElementValue.u2elementNameIndex != 0) + { + markCpUtf8Entry(clazz, constantElementValue.u2elementNameIndex); + } + + // Only the string constant element value refers to a UTF-8 entry. + if (constantElementValue.u1tag == ClassConstants.ELEMENT_VALUE_STRING_CONSTANT) + { + markCpUtf8Entry(clazz, constantElementValue.u2constantValueIndex); + } + } + + + public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) + { + if (enumConstantElementValue.u2elementNameIndex != 0) + { + markCpUtf8Entry(clazz, enumConstantElementValue.u2elementNameIndex); + } + + markCpUtf8Entry(clazz, enumConstantElementValue.u2typeNameIndex); + markCpUtf8Entry(clazz, enumConstantElementValue.u2constantNameIndex); + } + + + public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) + { + if (classElementValue.u2elementNameIndex != 0) + { + markCpUtf8Entry(clazz, classElementValue.u2elementNameIndex); + } + + markCpUtf8Entry(clazz, classElementValue.u2classInfoIndex); + } + + + public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) + { + if (annotationElementValue.u2elementNameIndex != 0) + { + markCpUtf8Entry(clazz, annotationElementValue.u2elementNameIndex); + } + + // Mark the UTF-8 entries referenced by the annotation. + annotationElementValue.annotationAccept(clazz, this); + } + + + public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) + { + if (arrayElementValue.u2elementNameIndex != 0) + { + markCpUtf8Entry(clazz, arrayElementValue.u2elementNameIndex); + } + + // Mark the UTF-8 entries referenced by the element values. + arrayElementValue.elementValuesAccept(clazz, annotation, this); + } + + + // Small utility methods. + + /** + * Marks the given UTF-8 constant pool entry of the given class. + */ + private void markCpUtf8Entry(Clazz clazz, int index) + { + markAsUsed((Utf8Constant)((ProgramClass)clazz).getConstant(index)); + } + + + /** + * Marks the given VisitorAccepter as being used. + * In this context, the VisitorAccepter will be a Utf8Constant object. + */ + private void markAsUsed(VisitorAccepter visitorAccepter) + { + visitorAccepter.setVisitorInfo(USED); + } + + + /** + * Returns whether the given VisitorAccepter has been marked as being used. + * In this context, the VisitorAccepter will be a Utf8Constant object. + */ + private boolean isUsed(VisitorAccepter visitorAccepter) + { + return visitorAccepter.getVisitorInfo() == USED; + } + + + /** + * Removes all UTF-8 entries that are not marked as being used + * from the given constant pool. + * @return the new number of entries. + */ + private int shrinkConstantPool(Constant[] constantPool, int length) + { + // Create a new index map, if necessary. + 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]; + + // Don't update the flag if this is the second half of a long entry. + if (constant != null) + { + isUsed = constant.getTag() != ClassConstants.CONSTANT_Utf8 || + isUsed(constant); + } + + if (isUsed) + { + constantPool[counter++] = constant; + } + } + + // Clear the remaining constant pool elements. + Arrays.fill(constantPool, counter, length, null); + + return counter; + } +} diff --git a/src/proguard/classfile/editor/VariableCleaner.java b/src/proguard/classfile/editor/VariableCleaner.java index 1e93c15..af51403 100644 --- a/src/proguard/classfile/editor/VariableCleaner.java +++ b/src/proguard/classfile/editor/VariableCleaner.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-2011 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 @@ -22,15 +22,15 @@ package proguard.classfile.editor; import proguard.classfile.*; import proguard.classfile.attribute.*; -import proguard.classfile.attribute.visitor.*; -import proguard.classfile.instruction.*; -import proguard.classfile.instruction.visitor.InstructionVisitor; +import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; -import proguard.optimize.info.VariableUsageMarker; + +import java.util.Arrays; /** - * This AttributeVisitor cleans up unused variables in all attributes that it - * visits. + * This AttributeVisitor cleans up variable tables in all code attributes that + * it visits. It trims overlapping local variables. It removes empty local + * variables and empty local variable tables. * * @author Eric Lafortune */ @@ -38,7 +38,8 @@ public class VariableCleaner extends SimplifiedVisitor implements AttributeVisitor { - private final VariableUsageMarker variableUsageMarker = new VariableUsageMarker(); + private boolean deleteLocalVariableTableAttribute; + private boolean deleteLocalVariableTypeTableAttribute; // Implementations for AttributeVisitor. @@ -48,11 +49,35 @@ implements AttributeVisitor public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { - // Figure out the local variables that are used by the code. - variableUsageMarker.visitCodeAttribute(clazz, method, codeAttribute); + deleteLocalVariableTableAttribute = false; + deleteLocalVariableTypeTableAttribute = false; - // Clean up the variables of the attributes. + // Trim the local variable table and the local variable type table. codeAttribute.attributesAccept(clazz, method, this); + + // Delete the local variable table if it ended up empty. + if (deleteLocalVariableTableAttribute) + { + AttributesEditor editor = + new AttributesEditor((ProgramClass)clazz, + (ProgramMember)method, + codeAttribute, + true); + + editor.deleteAttribute(ClassConstants.ATTR_LocalVariableTable); + } + + // Delete the local variable type table if it ended up empty. + if (deleteLocalVariableTypeTableAttribute) + { + AttributesEditor editor = + new AttributesEditor((ProgramClass)clazz, + (ProgramMember)method, + codeAttribute, + true); + + editor.deleteAttribute(ClassConstants.ATTR_LocalVariableTypeTable); + } } @@ -60,9 +85,20 @@ implements AttributeVisitor { // Clean up local variables that aren't used. localVariableTableAttribute.u2localVariableTableLength = - removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable, - localVariableTableAttribute.u2localVariableTableLength, - codeAttribute.u2maxLocals); + removeUnusedLocalVariables(localVariableTableAttribute.localVariableTable, + localVariableTableAttribute.u2localVariableTableLength, + codeAttribute.u2maxLocals); + + // Trim the code blocks of the local variables. + trimLocalVariables(localVariableTableAttribute.localVariableTable, + localVariableTableAttribute.u2localVariableTableLength, + codeAttribute.u2maxLocals); + + // Delete the attribute in a moment, if it is empty. + if (localVariableTableAttribute.u2localVariableTableLength == 0) + { + deleteLocalVariableTableAttribute = true; + } } @@ -70,9 +106,20 @@ implements AttributeVisitor { // Clean up local variables that aren't used. localVariableTypeTableAttribute.u2localVariableTypeTableLength = - removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, - localVariableTypeTableAttribute.u2localVariableTypeTableLength, - codeAttribute.u2maxLocals); + removeUnusedLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, + localVariableTypeTableAttribute.u2localVariableTypeTableLength, + codeAttribute.u2maxLocals); + + // Trim the code blocks of the local variables. + trimLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, + localVariableTypeTableAttribute.u2localVariableTypeTableLength, + codeAttribute.u2maxLocals); + + // Delete the attribute in a moment, if it is empty. + if (localVariableTypeTableAttribute.u2localVariableTypeTableLength == 0) + { + deleteLocalVariableTypeTableAttribute = true; + } } @@ -80,27 +127,28 @@ implements AttributeVisitor /** * Returns the given list of local variables, without the ones that aren't - * used + * used. */ - private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos, - int localVariableInfoCount, - int maxLocals) + private int removeUnusedLocalVariables(LocalVariableInfo[] localVariableInfos, + int localVariableInfoCount, + int maxLocals) { // Overwrite all empty local variable entries. int newIndex = 0; - for (int index = 0; index < localVariableInfoCount && index < maxLocals; index++) + for (int index = 0; index < localVariableInfoCount; index++) { - if (variableUsageMarker.isVariableUsed(index)) + LocalVariableInfo localVariableInfo = localVariableInfos[index]; + + if (localVariableInfo.u2index >= 0 && + localVariableInfo.u2index < maxLocals && + localVariableInfo.u2length > 0) { localVariableInfos[newIndex++] = localVariableInfos[index]; } } // Clean up any remaining array elements. - for (int index = newIndex; index < localVariableInfoCount; index++) - { - localVariableInfos[index] = null; - } + Arrays.fill(localVariableInfos, newIndex, localVariableInfoCount, null); return newIndex; } @@ -108,28 +156,112 @@ implements AttributeVisitor /** * Returns the given list of local variable types, without the ones that - * aren't used + * aren't used. */ - private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, - int localVariableTypeInfoCount, - int maxLocals) + private int removeUnusedLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, + int localVariableTypeInfoCount, + int maxLocals) { // Overwrite all empty local variable type entries. int newIndex = 0; - for (int index = 0; index < localVariableTypeInfoCount && index < maxLocals; index++) + for (int index = 0; index < localVariableTypeInfoCount; index++) { - if (variableUsageMarker.isVariableUsed(index)) + LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; + + if (localVariableTypeInfo.u2index >= 0 && + localVariableTypeInfo.u2index < maxLocals && + localVariableTypeInfo.u2length > 0) { localVariableTypeInfos[newIndex++] = localVariableTypeInfos[index]; } } // Clean up any remaining array elements. - for (int index = newIndex; index < localVariableTypeInfoCount; index++) + Arrays.fill(localVariableTypeInfos, newIndex, localVariableTypeInfoCount, null); + + return newIndex; + } + + + /** + * Sorts the given list of local variables and trims their code blocks + * when necessary. The block is trimmed at the end, which is a bit + * arbitrary. + */ + private void trimLocalVariables(LocalVariableInfo[] localVariableInfos, + int localVariableInfoCount, + int maxLocals) + { + // Sort the local variable entries. + Arrays.sort(localVariableInfos, 0, localVariableInfoCount); + + int[] startPCs = createMaxArray(maxLocals); + + // Trim the local variable entries, starting at the last one. + for (int index = localVariableInfoCount-1; index >= 0; index--) { - localVariableTypeInfos[index] = null; + LocalVariableInfo localVariableInfo = localVariableInfos[index]; + + // Make sure the variable's code block doesn't overlap with the + // next one for the same variable. + int maxLength = startPCs[localVariableInfo.u2index] - + localVariableInfo.u2startPC; + + if (localVariableInfo.u2length > maxLength) + { + localVariableInfo.u2length = maxLength; + } + + startPCs[localVariableInfo.u2index] = localVariableInfo.u2startPC; } + } - return newIndex; + + /** + * Sorts the given list of local variable types and trims their code blocks + * when necessary. The block is trimmed at the end, which is a bit + * arbitrary. + */ + private void trimLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, + int localVariableTypeInfoCount, + int maxLocals) + { + // Sort the local variable entries. + Arrays.sort(localVariableTypeInfos, 0, localVariableTypeInfoCount); + + int[] startPCs = createMaxArray(maxLocals); + + // Trim the local variable entries, starting at the last one. + for (int index = localVariableTypeInfoCount-1; index >= 0; index--) + { + LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; + + // Make sure the variable's code block doesn't overlap with the + // next one for the same variable. + int maxLength = startPCs[localVariableTypeInfo.u2index] - + localVariableTypeInfo.u2startPC; + + if (localVariableTypeInfo.u2length > maxLength) + { + localVariableTypeInfo.u2length = maxLength; + } + + startPCs[localVariableTypeInfo.u2index] = localVariableTypeInfo.u2startPC; + } + } + + + /** + * Creates an integer array of the given length, initialized with + * Integer.MAX_VALUE. + */ + private int[] createMaxArray(int length) + { + int[] startPCs = new int[length]; + for (int index = 0; index < length; index++) + { + startPCs[index] = Integer.MAX_VALUE; + } + return startPCs; } }
\ No newline at end of file diff --git a/src/proguard/classfile/editor/VariableEditor.java b/src/proguard/classfile/editor/VariableEditor.java index a583b49..8c99ff8 100644 --- a/src/proguard/classfile/editor/VariableEditor.java +++ b/src/proguard/classfile/editor/VariableEditor.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-2011 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 @@ -25,6 +25,8 @@ import proguard.classfile.attribute.*; import proguard.classfile.attribute.visitor.AttributeVisitor; import proguard.classfile.util.SimplifiedVisitor; +import java.util.Arrays; + /** * This AttributeVisitor accumulates specified changes to local variables, and * then applies these accumulated changes to the code attributes that it visits. @@ -53,14 +55,13 @@ implements AttributeVisitor // Try to reuse the previous array. if (deleted.length < maxLocals) { + // Create a new array. deleted = new boolean[maxLocals]; } else { - for (int index = 0; index < maxLocals; index++) - { - deleted[index] = false; - } + // Reset the array. + Arrays.fill(deleted, 0, maxLocals, false); } modified = false; diff --git a/src/proguard/classfile/editor/VariableRemapper.java b/src/proguard/classfile/editor/VariableRemapper.java index 590cd4e..df26534 100644 --- a/src/proguard/classfile/editor/VariableRemapper.java +++ b/src/proguard/classfile/editor/VariableRemapper.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-2011 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 @@ -40,6 +40,9 @@ implements AttributeVisitor, LocalVariableInfoVisitor, LocalVariableTypeInfoVisitor { + private static final boolean DEBUG = false; + + private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); private int[] variableMap; @@ -62,6 +65,19 @@ implements AttributeVisitor, public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) { + if (DEBUG) + { + System.out.println("VariableRemapper: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); + for (int index= 0; index < codeAttribute.u2maxLocals; index++) + { + System.out.println(" v"+index+" -> "+variableMap[index]); + } + } + + // Remap the variables of the attributes, before editing the code and + // cleaning up its local variable frame. + codeAttribute.attributesAccept(clazz, method, this); + // Initially, the code attribute editor doesn't contain any changes. codeAttributeEditor.reset(codeAttribute.u4codeLength); @@ -70,9 +86,6 @@ implements AttributeVisitor, // Apply the code atribute editor. codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); - - // Remap the variables of the attributes. - codeAttribute.attributesAccept(clazz, method, this); } @@ -80,11 +93,6 @@ implements AttributeVisitor, { // Remap the variable references of the local variables. localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - - // Remove local variables that haven't been mapped. - localVariableTableAttribute.u2localVariableTableLength = - removeEmptyLocalVariables(localVariableTableAttribute.localVariableTable, - localVariableTableAttribute.u2localVariableTableLength); } @@ -92,11 +100,6 @@ implements AttributeVisitor, { // Remap the variable references of the local variables. localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); - - // Remove local variables that haven't been mapped. - localVariableTypeTableAttribute.u2localVariableTypeTableLength = - removeEmptyLocalVariableTypes(localVariableTypeTableAttribute.localVariableTypeTable, - localVariableTypeTableAttribute.u2localVariableTypeTableLength); } @@ -150,48 +153,4 @@ implements AttributeVisitor, { return variableMap[variableIndex]; } - - - /** - * Returns the given list of local variables, without the ones that have - * been removed. - */ - private int removeEmptyLocalVariables(LocalVariableInfo[] localVariableInfos, - int localVariableInfoCount) - { - // Overwrite all empty local variable entries. - int newIndex = 0; - for (int index = 0; index < localVariableInfoCount; index++) - { - LocalVariableInfo localVariableInfo = localVariableInfos[index]; - if (localVariableInfo.u2index >= 0) - { - localVariableInfos[newIndex++] = localVariableInfo; - } - } - - return newIndex; - } - - - /** - * Returns the given list of local variable types, without the ones that - * have been removed. - */ - private int removeEmptyLocalVariableTypes(LocalVariableTypeInfo[] localVariableTypeInfos, - int localVariableTypeInfoCount) - { - // Overwrite all empty local variable type entries. - int newIndex = 0; - for (int index = 0; index < localVariableTypeInfoCount; index++) - { - LocalVariableTypeInfo localVariableTypeInfo = localVariableTypeInfos[index]; - if (localVariableTypeInfo.u2index >= 0) - { - localVariableTypeInfos[newIndex++] = localVariableTypeInfo; - } - } - - return newIndex; - } } diff --git a/src/proguard/classfile/editor/VariableSizeUpdater.java b/src/proguard/classfile/editor/VariableSizeUpdater.java index 18958c5..bb87151 100644 --- a/src/proguard/classfile/editor/VariableSizeUpdater.java +++ b/src/proguard/classfile/editor/VariableSizeUpdater.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-2011 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 @@ -29,7 +29,8 @@ import proguard.classfile.util.*; /** * This AttributeVisitor computes and updates the maximum local variable frame - * size of the code attributes that it visits. + * size of the code attributes that it visits. It also cleans up the local + * variable tables. * * @author Eric Lafortune */ @@ -45,6 +46,9 @@ implements AttributeVisitor, //*/ + private VariableCleaner variableCleaner = new VariableCleaner(); + + // Implementations for AttributeVisitor. public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} @@ -69,6 +73,9 @@ implements AttributeVisitor, // Go over all instructions. codeAttribute.instructionsAccept(clazz, method, this); + + // Remove the unused variables of the attributes. + variableCleaner.visitCodeAttribute(clazz, method, codeAttribute); } @@ -91,7 +98,7 @@ implements AttributeVisitor, if (DEBUG) { - System.out.println("Max locals: "+codeAttribute.u2maxLocals+" <- "+variableInstruction.toString(offset)); + System.out.println(" Max locals: "+codeAttribute.u2maxLocals+" <- "+variableInstruction.toString(offset)); } } } |