diff options
Diffstat (limited to 'src/proguard/classfile/editor/ConstantPoolRemapper.java')
-rw-r--r-- | src/proguard/classfile/editor/ConstantPoolRemapper.java | 617 |
1 files changed, 617 insertions, 0 deletions
diff --git a/src/proguard/classfile/editor/ConstantPoolRemapper.java b/src/proguard/classfile/editor/ConstantPoolRemapper.java new file mode 100644 index 0000000..7430d3d --- /dev/null +++ b/src/proguard/classfile/editor/ConstantPoolRemapper.java @@ -0,0 +1,617 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2009 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.*; + +/** + * This ClassVisitor remaps all possible references to constant pool entries + * of the classes that it visits, based on a given index map. It is assumed that + * the constant pool entries themselves have already been remapped. + * + * @author Eric Lafortune + */ +public class ConstantPoolRemapper +extends SimplifiedVisitor +implements ClassVisitor, + ConstantVisitor, + MemberVisitor, + AttributeVisitor, + InstructionVisitor, + InnerClassesInfoVisitor, + ExceptionInfoVisitor, + StackMapFrameVisitor, + VerificationTypeVisitor, + LocalVariableInfoVisitor, + LocalVariableTypeInfoVisitor, + AnnotationVisitor, + ElementValueVisitor +{ + private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); + + private int[] constantIndexMap; + + + /** + * Sets the given mapping of old constant pool entry indexes to their new + * indexes. + */ + public void setConstantIndexMap(int[] constantIndexMap) + { + this.constantIndexMap = constantIndexMap; + } + + + // Implementations for ClassVisitor. + + public void visitProgramClass(ProgramClass programClass) + { + // Remap the local constant pool references. + programClass.u2thisClass = remapConstantIndex(programClass.u2thisClass); + programClass.u2superClass = remapConstantIndex(programClass.u2superClass); + + remapConstantIndexArray(programClass.u2interfaces, + programClass.u2interfacesCount); + + // Remap the references of the contant pool entries themselves. + programClass.constantPoolEntriesAccept(this); + + // Remap the references in all fields, methods, and attributes. + programClass.fieldsAccept(this); + programClass.methodsAccept(this); + programClass.attributesAccept(this); + } + + + public void visitLibraryClass(LibraryClass libraryClass) + { + } + + + // Implementations for ConstantVisitor. + + public void visitClassConstant(Clazz clazz, ClassConstant classConstant) + { + classConstant.u2nameIndex = + remapConstantIndex(classConstant.u2nameIndex); + } + + + public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) + { + // Nothing to do. + } + + + public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) + { + fieldrefConstant.u2classIndex = + remapConstantIndex(fieldrefConstant.u2classIndex); + fieldrefConstant.u2nameAndTypeIndex = + remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex); + } + + + public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) + { + // Nothing to do. + } + + + public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) + { + // Nothing to do. + } + + + public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) + { + interfaceMethodrefConstant.u2classIndex = + remapConstantIndex(interfaceMethodrefConstant.u2classIndex); + interfaceMethodrefConstant.u2nameAndTypeIndex = + remapConstantIndex(interfaceMethodrefConstant.u2nameAndTypeIndex); + } + + + public void visitLongConstant(Clazz clazz, LongConstant longConstant) + { + // Nothing to do. + } + + + public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) + { + methodrefConstant.u2classIndex = + remapConstantIndex(methodrefConstant.u2classIndex); + methodrefConstant.u2nameAndTypeIndex = + remapConstantIndex(methodrefConstant.u2nameAndTypeIndex); + } + + + public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) + { + nameAndTypeConstant.u2nameIndex = + remapConstantIndex(nameAndTypeConstant.u2nameIndex); + nameAndTypeConstant.u2descriptorIndex = + remapConstantIndex(nameAndTypeConstant.u2descriptorIndex); + } + + + public void visitStringConstant(Clazz clazz, StringConstant stringConstant) + { + stringConstant.u2stringIndex = + remapConstantIndex(stringConstant.u2stringIndex); + } + + + public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) + { + // Nothing to do. + } + + + // Implementations for MemberVisitor. + + public void visitProgramField(ProgramClass programClass, ProgramField programField) + { + visitMember(programClass, programField); + } + + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + visitMember(programClass, programMethod); + } + + + private void visitMember(ProgramClass programClass, ProgramMember programMember) + { + // Remap the local constant pool references. + programMember.u2nameIndex = + remapConstantIndex(programMember.u2nameIndex); + programMember.u2descriptorIndex = + remapConstantIndex(programMember.u2descriptorIndex); + + // Remap the constant pool references of the remaining attributes. + programMember.attributesAccept(programClass, this); + } + + + public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) + { + // Library classes are left unchanged. + } + + + public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) + { + // Library classes are left unchanged. + } + + + // Implementations for AttributeVisitor. + + public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) + { + unknownAttribute.u2attributeNameIndex = + remapConstantIndex(unknownAttribute.u2attributeNameIndex); + + // There's not much else we can do with unknown attributes. + } + + + public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) + { + sourceFileAttribute.u2attributeNameIndex = + remapConstantIndex(sourceFileAttribute.u2attributeNameIndex); + sourceFileAttribute.u2sourceFileIndex = + remapConstantIndex(sourceFileAttribute.u2sourceFileIndex); + } + + + public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) + { + sourceDirAttribute.u2attributeNameIndex = + remapConstantIndex(sourceDirAttribute.u2attributeNameIndex); + sourceDirAttribute.u2sourceDirIndex = + remapConstantIndex(sourceDirAttribute.u2sourceDirIndex); + } + + + public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) + { + innerClassesAttribute.u2attributeNameIndex = + remapConstantIndex(innerClassesAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the inner classes. + innerClassesAttribute.innerClassEntriesAccept(clazz, this); + } + + + public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) + { + enclosingMethodAttribute.u2attributeNameIndex = + remapConstantIndex(enclosingMethodAttribute.u2attributeNameIndex); + enclosingMethodAttribute.u2classIndex = + remapConstantIndex(enclosingMethodAttribute.u2classIndex); + enclosingMethodAttribute.u2nameAndTypeIndex = + remapConstantIndex(enclosingMethodAttribute.u2nameAndTypeIndex); + } + + + public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) + { + deprecatedAttribute.u2attributeNameIndex = + remapConstantIndex(deprecatedAttribute.u2attributeNameIndex); + } + + + public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) + { + syntheticAttribute.u2attributeNameIndex = + remapConstantIndex(syntheticAttribute.u2attributeNameIndex); + } + + + public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) + { + signatureAttribute.u2attributeNameIndex = + remapConstantIndex(signatureAttribute.u2attributeNameIndex); + signatureAttribute.u2signatureIndex = + remapConstantIndex(signatureAttribute.u2signatureIndex); + } + + + public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) + { + constantValueAttribute.u2attributeNameIndex = + remapConstantIndex(constantValueAttribute.u2attributeNameIndex); + constantValueAttribute.u2constantValueIndex = + remapConstantIndex(constantValueAttribute.u2constantValueIndex); + } + + + public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) + { + exceptionsAttribute.u2attributeNameIndex = + remapConstantIndex(exceptionsAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the exceptions. + remapConstantIndexArray(exceptionsAttribute.u2exceptionIndexTable, + exceptionsAttribute.u2exceptionIndexTableLength); + } + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + codeAttribute.u2attributeNameIndex = + remapConstantIndex(codeAttribute.u2attributeNameIndex); + + // Initially, the code attribute editor doesn't contain any changes. + codeAttributeEditor.reset(codeAttribute.u4codeLength); + + // Remap the constant pool references of the instructions. + codeAttribute.instructionsAccept(clazz, method, this); + + // Apply the code atribute editor. It will only contain any changes if + // the code length is changing at any point. + codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); + + // Remap the constant pool references of the exceptions and attributes. + codeAttribute.exceptionsAccept(clazz, method, this); + codeAttribute.attributesAccept(clazz, method, this); + } + + + public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) + { + stackMapAttribute.u2attributeNameIndex = + remapConstantIndex(stackMapAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the stack map frames. + stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); + } + + + public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) + { + stackMapTableAttribute.u2attributeNameIndex = + remapConstantIndex(stackMapTableAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the stack map frames. + stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); + } + + + public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) + { + lineNumberTableAttribute.u2attributeNameIndex = + remapConstantIndex(lineNumberTableAttribute.u2attributeNameIndex); + } + + + public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) + { + localVariableTableAttribute.u2attributeNameIndex = + remapConstantIndex(localVariableTableAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the local variables. + localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + } + + + public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) + { + localVariableTypeTableAttribute.u2attributeNameIndex = + remapConstantIndex(localVariableTypeTableAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the local variables. + localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); + } + + + public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) + { + annotationsAttribute.u2attributeNameIndex = + remapConstantIndex(annotationsAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the annotations. + annotationsAttribute.annotationsAccept(clazz, this); + } + + + public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) + { + parameterAnnotationsAttribute.u2attributeNameIndex = + remapConstantIndex(parameterAnnotationsAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the annotations. + parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); + } + + + public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) + { + annotationDefaultAttribute.u2attributeNameIndex = + remapConstantIndex(annotationDefaultAttribute.u2attributeNameIndex); + + // Remap the constant pool references of the annotations. + annotationDefaultAttribute.defaultValueAccept(clazz, this); + } + + + // Implementations for InnerClassesInfoVisitor. + + public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) + { + if (innerClassesInfo.u2innerClassIndex != 0) + { + innerClassesInfo.u2innerClassIndex = + remapConstantIndex(innerClassesInfo.u2innerClassIndex); + } + + if (innerClassesInfo.u2outerClassIndex != 0) + { + innerClassesInfo.u2outerClassIndex = + remapConstantIndex(innerClassesInfo.u2outerClassIndex); + } + + if (innerClassesInfo.u2innerNameIndex != 0) + { + innerClassesInfo.u2innerNameIndex = + remapConstantIndex(innerClassesInfo.u2innerNameIndex); + } + } + + + // Implementations for ExceptionInfoVisitor. + + public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) + { + if (exceptionInfo.u2catchType != 0) + { + exceptionInfo.u2catchType = + remapConstantIndex(exceptionInfo.u2catchType); + } + } + + + // 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) + { + // Is the new constant pool index different from the original one? + int newConstantIndex = remapConstantIndex(constantInstruction.constantIndex); + if (newConstantIndex != constantInstruction.constantIndex) + { + // Replace the instruction. + Instruction replacementInstruction = + new ConstantInstruction(constantInstruction.opcode, + newConstantIndex, + constantInstruction.constant).shrink(); + + codeAttributeEditor.replaceInstruction(offset, replacementInstruction); + } + } + + + // 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) + { + // Remap the constant pool references of the verification types. + sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); + } + + + public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) + { + // Remap the constant pool references of the verification types. + moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); + } + + + public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) + { + // Remap the constant pool references of 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) + { + objectType.u2classIndex = + remapConstantIndex(objectType.u2classIndex); + } + + + // Implementations for LocalVariableInfoVisitor. + + public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) + { + localVariableInfo.u2nameIndex = + remapConstantIndex(localVariableInfo.u2nameIndex); + localVariableInfo.u2descriptorIndex = + remapConstantIndex(localVariableInfo.u2descriptorIndex); + } + + + // Implementations for LocalVariableTypeInfoVisitor. + + public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) + { + localVariableTypeInfo.u2nameIndex = + remapConstantIndex(localVariableTypeInfo.u2nameIndex); + localVariableTypeInfo.u2signatureIndex = + remapConstantIndex(localVariableTypeInfo.u2signatureIndex); + } + + + // Implementations for AnnotationVisitor. + + public void visitAnnotation(Clazz clazz, Annotation annotation) + { + annotation.u2typeIndex = + remapConstantIndex(annotation.u2typeIndex); + + // Remap the constant pool references of the element values. + annotation.elementValuesAccept(clazz, this); + } + + + // Implementations for ElementValueVisitor. + + public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) + { + constantElementValue.u2elementNameIndex = + remapConstantIndex(constantElementValue.u2elementNameIndex); + constantElementValue.u2constantValueIndex = + remapConstantIndex(constantElementValue.u2constantValueIndex); + } + + + public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) + { + enumConstantElementValue.u2elementNameIndex = + remapConstantIndex(enumConstantElementValue.u2elementNameIndex); + enumConstantElementValue.u2typeNameIndex = + remapConstantIndex(enumConstantElementValue.u2typeNameIndex); + enumConstantElementValue.u2constantNameIndex = + remapConstantIndex(enumConstantElementValue.u2constantNameIndex); + } + + + public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) + { + classElementValue.u2elementNameIndex = + remapConstantIndex(classElementValue.u2elementNameIndex); + classElementValue.u2classInfoIndex = + remapConstantIndex(classElementValue.u2classInfoIndex); + } + + + public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) + { + annotationElementValue.u2elementNameIndex = + remapConstantIndex(annotationElementValue.u2elementNameIndex); + + // Remap the constant pool references of the annotation. + annotationElementValue.annotationAccept(clazz, this); + } + + + public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) + { + arrayElementValue.u2elementNameIndex = + remapConstantIndex(arrayElementValue.u2elementNameIndex); + + // Remap the constant pool references of the element values. + arrayElementValue.elementValuesAccept(clazz, annotation, this); + } + + + // Small utility methods. + + /** + * Remaps all constant pool indices in the given array. + */ + private void remapConstantIndexArray(int[] array, int length) + { + for (int index = 0; index < length; index++) + { + array[index] = remapConstantIndex(array[index]); + } + } + + + /** + * Returns the new constant pool index of the entry at the + * given index. + */ + private int remapConstantIndex(int constantIndex) + { + return constantIndexMap[constantIndex]; + } +} |