diff options
Diffstat (limited to 'third_party/java/proguard/proguard5.3.3/src/proguard/optimize/DuplicateInitializerFixer.java')
-rw-r--r-- | third_party/java/proguard/proguard5.3.3/src/proguard/optimize/DuplicateInitializerFixer.java | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/third_party/java/proguard/proguard5.3.3/src/proguard/optimize/DuplicateInitializerFixer.java b/third_party/java/proguard/proguard5.3.3/src/proguard/optimize/DuplicateInitializerFixer.java new file mode 100644 index 0000000000..a255343901 --- /dev/null +++ b/third_party/java/proguard/proguard5.3.3/src/proguard/optimize/DuplicateInitializerFixer.java @@ -0,0 +1,215 @@ +/* + * ProGuard -- shrinking, optimization, obfuscation, and preverification + * of Java bytecode. + * + * Copyright (c) 2002-2017 Eric Lafortune @ GuardSquare + * + * 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.optimize; + +import proguard.classfile.*; +import proguard.classfile.attribute.*; +import proguard.classfile.attribute.annotation.*; +import proguard.classfile.attribute.visitor.AttributeVisitor; +import proguard.classfile.editor.ConstantPoolEditor; +import proguard.classfile.util.*; +import proguard.classfile.visitor.MemberVisitor; + +/** + * This MemberVisitor adds an additional parameter to the duplicate + * initialization methods that it visits. + */ +public class DuplicateInitializerFixer +extends SimplifiedVisitor +implements MemberVisitor, + AttributeVisitor +{ + private static final boolean DEBUG = false; + + private static final char[] TYPES = new char[] + { + ClassConstants.TYPE_BYTE, + ClassConstants.TYPE_CHAR, + ClassConstants.TYPE_SHORT, + ClassConstants.TYPE_INT, + ClassConstants.TYPE_BOOLEAN + }; + + + private final MemberVisitor extraFixedInitializerVisitor; + + + /** + * Creates a new DuplicateInitializerFixer. + */ + public DuplicateInitializerFixer() + { + this(null); + } + + + /** + * Creates a new DuplicateInitializerFixer with an extra visitor. + * @param extraFixedInitializerVisitor an optional extra visitor for all + * initializers that have been fixed. + */ + public DuplicateInitializerFixer(MemberVisitor extraFixedInitializerVisitor) + { + this.extraFixedInitializerVisitor = extraFixedInitializerVisitor; + } + + + // Implementations for MemberVisitor. + + public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) + { + // Is it a class instance initializer? + String name = programMethod.getName(programClass); + if (name.equals(ClassConstants.METHOD_NAME_INIT)) + { + // Is there already another initializer with the same descriptor? + String descriptor = programMethod.getDescriptor(programClass); + Method similarMethod = programClass.findMethod(name, descriptor); + if (!programMethod.equals(similarMethod)) + { + // Should this initializer be preserved? + if (KeepMarker.isKept(programMethod)) + { + // Fix the other initializer. + programMethod = (ProgramMethod)similarMethod; + } + + int index = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); + + // Try to find a new, unique descriptor. + int typeCounter = 0; + while (true) + { + // Construct the new descriptor by inserting a new type + // as an additional last argument. + StringBuffer newDescriptorBuffer = + new StringBuffer(descriptor.substring(0, index)); + + for (int arrayDimension = 0; arrayDimension < typeCounter / TYPES.length; arrayDimension++) + { + newDescriptorBuffer.append(ClassConstants.TYPE_ARRAY); + } + + newDescriptorBuffer.append(TYPES[typeCounter % TYPES.length]); + newDescriptorBuffer.append(descriptor.substring(index)); + + String newDescriptor = newDescriptorBuffer.toString(); + + // Is the new initializer descriptor unique? + if (programClass.findMethod(name, newDescriptor) == null) + { + if (DEBUG) + { + System.out.println("DuplicateInitializerFixer:"); + System.out.println(" ["+programClass.getName()+"."+name+descriptor+"] ("+ClassUtil.externalClassAccessFlags(programMethod.getAccessFlags())+") -> ["+newDescriptor+"]"); + } + + // Update the descriptor. + programMethod.u2descriptorIndex = + new ConstantPoolEditor(programClass).addUtf8Constant(newDescriptor); + + // Fix the local variable frame size, the method + // signature, and the parameter annotations, if + // necessary. + programMethod.attributesAccept(programClass, + this); + + // Visit the initializer, if required. + if (extraFixedInitializerVisitor != null) + { + extraFixedInitializerVisitor.visitProgramMethod(programClass, programMethod); + } + + // We're done with this constructor. + return; + } + + typeCounter++; + } + } + } + } + + + // Implementations for AttributeVisitor. + + public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} + + + public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) + { + // The minimum variable size is determined by the arguments. + int maxLocals = + ClassUtil.internalMethodParameterSize(method.getDescriptor(clazz), + method.getAccessFlags()); + + if (codeAttribute.u2maxLocals < maxLocals) + { + codeAttribute.u2maxLocals = maxLocals; + } + } + + + public void visitSignatureAttribute(Clazz clazz, Method method, SignatureAttribute signatureAttribute) + { + String descriptor = method.getDescriptor(clazz); + int descriptorIndex = descriptor.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); + String signature = signatureAttribute.getSignature(clazz); + int signatureIndex = signature.indexOf(ClassConstants.METHOD_ARGUMENTS_CLOSE); + + String newSignature = signature.substring(0, signatureIndex) + + descriptor.charAt(descriptorIndex - 1) + + signature.substring(signatureIndex); + + // Update the signature. + signatureAttribute.u2signatureIndex = + new ConstantPoolEditor((ProgramClass)clazz).addUtf8Constant(newSignature); + } + + + public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) + { + // Update the number of parameters. + int oldParametersCount = parameterAnnotationsAttribute.u1parametersCount++; + + if (parameterAnnotationsAttribute.u2parameterAnnotationsCount == null || + parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u1parametersCount) + { + int[] annotationsCounts = new int[parameterAnnotationsAttribute.u1parametersCount]; + Annotation[][] annotations = new Annotation[parameterAnnotationsAttribute.u1parametersCount][]; + + System.arraycopy(parameterAnnotationsAttribute.u2parameterAnnotationsCount, + 0, + annotationsCounts, + 0, + oldParametersCount); + + System.arraycopy(parameterAnnotationsAttribute.parameterAnnotations, + 0, + annotations, + 0, + oldParametersCount); + + parameterAnnotationsAttribute.u2parameterAnnotationsCount = annotationsCounts; + parameterAnnotationsAttribute.parameterAnnotations = annotations; + } + } +}
\ No newline at end of file |