001: /*
002: * ProGuard -- shrinking, optimization, obfuscation, and preverification
003: * of Java bytecode.
004: *
005: * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
006: *
007: * This program is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License as published by the Free
009: * Software Foundation; either version 2 of the License, or (at your option)
010: * any later version.
011: *
012: * This program is distributed in the hope that it will be useful, but WITHOUT
013: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
015: * more details.
016: *
017: * You should have received a copy of the GNU General Public License along
018: * with this program; if not, write to the Free Software Foundation, Inc.,
019: * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
020: */
021: package proguard.optimize;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.attribute.visitor.AttributeVisitor;
025: import proguard.classfile.attribute.*;
026: import proguard.classfile.attribute.annotation.*;
027: import proguard.classfile.editor.ConstantPoolEditor;
028: import proguard.classfile.util.*;
029: import proguard.classfile.visitor.MemberVisitor;
030:
031: /**
032: * This MemberVisitor adds an additional parameter to the duplicate
033: * initialization methods that it visits.
034: */
035: public class DuplicateInitializerFixer extends SimplifiedVisitor
036: implements MemberVisitor, AttributeVisitor {
037: private static final boolean DEBUG = false;
038:
039: private static final char[] TYPES = new char[] {
040: ClassConstants.INTERNAL_TYPE_BYTE,
041: ClassConstants.INTERNAL_TYPE_CHAR,
042: ClassConstants.INTERNAL_TYPE_SHORT,
043: ClassConstants.INTERNAL_TYPE_INT,
044: ClassConstants.INTERNAL_TYPE_BOOLEAN };
045:
046: private final MemberVisitor extraFixedInitializerVisitor;
047:
048: private final ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
049:
050: /**
051: * Creates a new DuplicateInitializerFixer.
052: */
053: public DuplicateInitializerFixer() {
054: this (null);
055: }
056:
057: /**
058: * Creates a new DuplicateInitializerFixer with an extra visitor.
059: * @param extraFixedInitializerVisitor an optional extra visitor for all
060: * initializers that have been fixed.
061: */
062: public DuplicateInitializerFixer(
063: MemberVisitor extraFixedInitializerVisitor) {
064: this .extraFixedInitializerVisitor = extraFixedInitializerVisitor;
065: }
066:
067: // Implementations for MemberVisitor.
068:
069: public void visitProgramMethod(ProgramClass programClass,
070: ProgramMethod programMethod) {
071: // Is it a class instance initializer?
072: String name = programMethod.getName(programClass);
073: if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) {
074: // Is there already another initializer with the same descriptor?
075: String descriptor = programMethod
076: .getDescriptor(programClass);
077: Method similarMethod = programClass.findMethod(name,
078: descriptor);
079: if (!programMethod.equals(similarMethod)) {
080: // Should this initializer be preserved?
081: if (!KeepMarker.isKept(programMethod)) {
082: // Fix the other initializer.
083: programMethod = (ProgramMethod) similarMethod;
084: }
085:
086: int index = descriptor
087: .indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
088:
089: // Try to find a new, unique descriptor.
090: for (int typeIndex = 0; typeIndex < TYPES.length; typeIndex++) {
091: String newDescriptor = descriptor.substring(0,
092: index)
093: + TYPES[typeIndex]
094: + descriptor.substring(index);
095:
096: // Is the new initializer descriptor unique?
097: if (programClass.findMethod(name, newDescriptor) == null) {
098: if (DEBUG) {
099: System.out
100: .println("DuplicateInitializerFixer:");
101: System.out.println(" ["
102: + programClass.getName() + "]: "
103: + name + descriptor + " -> "
104: + newDescriptor);
105: }
106:
107: // Update the descriptor.
108: programMethod.u2descriptorIndex = constantPoolEditor
109: .addUtf8Constant(programClass,
110: newDescriptor);
111:
112: // Fix the local variable frame size, the method
113: // signature, and the parameter annotations, if
114: // necessary.
115: programMethod.attributesAccept(programClass,
116: this );
117:
118: // Visit the initializer, if required.
119: if (extraFixedInitializerVisitor != null) {
120: extraFixedInitializerVisitor
121: .visitProgramMethod(programClass,
122: programMethod);
123: }
124:
125: // We're done with this constructor.
126: return;
127: }
128: }
129:
130: throw new IllegalStateException(
131: "Can't find unique constructor descriptor for ["
132: + programClass.getName()
133: + "."
134: + programMethod.getName(programClass)
135: + programMethod
136: .getDescriptor(programClass)
137: + "]");
138: }
139: }
140: }
141:
142: // Implementations for AttributeVisitor.
143:
144: public void visitAnyAttribute(Clazz clazz, Attribute attribute) {
145: }
146:
147: public void visitCodeAttribute(Clazz clazz, Method method,
148: CodeAttribute codeAttribute) {
149: // The minimum variable size is determined by the arguments.
150: int maxLocals = ClassUtil.internalMethodParameterSize(method
151: .getDescriptor(clazz), method.getAccessFlags());
152:
153: if (codeAttribute.u2maxLocals < maxLocals) {
154: codeAttribute.u2maxLocals = maxLocals;
155: }
156: }
157:
158: public void visitSignatureAttribute(Clazz clazz, Method method,
159: SignatureAttribute signatureAttribute) {
160: String descriptor = method.getDescriptor(clazz);
161: int descriptorIndex = descriptor
162: .indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
163: String signature = clazz
164: .getString(signatureAttribute.u2signatureIndex);
165: int signatureIndex = signature
166: .indexOf(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE);
167:
168: String newSignature = signature.substring(0, signatureIndex)
169: + descriptor.charAt(descriptorIndex - 1)
170: + signature.substring(signatureIndex);
171:
172: // Update the signature.
173: signatureAttribute.u2signatureIndex = constantPoolEditor
174: .addUtf8Constant((ProgramClass) clazz, newSignature);
175: }
176:
177: public void visitAnyParameterAnnotationsAttribute(Clazz clazz,
178: Method method,
179: ParameterAnnotationsAttribute parameterAnnotationsAttribute) {
180:
181: // Update the number of parameters.
182: int oldParametersCount = parameterAnnotationsAttribute.u2parametersCount++;
183:
184: if (parameterAnnotationsAttribute.u2parameterAnnotationsCount == null
185: || parameterAnnotationsAttribute.u2parameterAnnotationsCount.length < parameterAnnotationsAttribute.u2parametersCount) {
186: int[] annotationsCounts = new int[parameterAnnotationsAttribute.u2parametersCount];
187: Annotation[][] annotations = new Annotation[parameterAnnotationsAttribute.u2parametersCount][];
188:
189: System
190: .arraycopy(
191: parameterAnnotationsAttribute.u2parameterAnnotationsCount,
192: 0, annotationsCounts, 0, oldParametersCount);
193:
194: System.arraycopy(
195: parameterAnnotationsAttribute.parameterAnnotations,
196: 0, annotations, 0, oldParametersCount);
197:
198: parameterAnnotationsAttribute.u2parameterAnnotationsCount = annotationsCounts;
199: parameterAnnotationsAttribute.parameterAnnotations = annotations;
200: }
201: }
202: }
|