summaryrefslogtreecommitdiffstats
path: root/src/proguard/optimize/DuplicateInitializerFixer.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/proguard/optimize/DuplicateInitializerFixer.java')
-rw-r--r--src/proguard/optimize/DuplicateInitializerFixer.java207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/proguard/optimize/DuplicateInitializerFixer.java b/src/proguard/optimize/DuplicateInitializerFixer.java
new file mode 100644
index 0000000..746d182
--- /dev/null
+++ b/src/proguard/optimize/DuplicateInitializerFixer.java
@@ -0,0 +1,207 @@
+/*
+ * 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.optimize;
+
+import proguard.classfile.*;
+import proguard.classfile.attribute.visitor.AttributeVisitor;
+import proguard.classfile.attribute.*;
+import proguard.classfile.attribute.annotation.*;
+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.INTERNAL_TYPE_BYTE,
+ ClassConstants.INTERNAL_TYPE_CHAR,
+ ClassConstants.INTERNAL_TYPE_SHORT,
+ ClassConstants.INTERNAL_TYPE_INT,
+ ClassConstants.INTERNAL_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.INTERNAL_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.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+
+ // Try to find a new, unique descriptor.
+ for (int typeIndex = 0; typeIndex < TYPES.length; typeIndex++)
+ {
+ String newDescriptor =
+ descriptor.substring(0, index) +
+ TYPES[typeIndex] +
+ descriptor.substring(index);
+
+ // 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+" -> "+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;
+ }
+ }
+
+ throw new IllegalStateException("Can't find unique constructor descriptor for ["+
+ programClass.getName()+"."+
+ programMethod.getName(programClass)+
+ programMethod.getDescriptor(programClass)+"]");
+ }
+ }
+ }
+
+
+ // 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.INTERNAL_METHOD_ARGUMENTS_CLOSE);
+ String signature = clazz.getString(signatureAttribute.u2signatureIndex);
+ int signatureIndex = signature.indexOf(ClassConstants.INTERNAL_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.u2parametersCount++;
+
+ if (parameterAnnotationsAttribute.u2parameterAnnotationsCount == null ||
+ parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u2parametersCount)
+ {
+ int[] annotationsCounts = new int[parameterAnnotationsAttribute.u2parametersCount];
+ Annotation[][] annotations = new Annotation[parameterAnnotationsAttribute.u2parametersCount][];
+
+ 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