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.peephole;
022:
023: import proguard.classfile.*;
024: import proguard.classfile.attribute.*;
025: import proguard.classfile.attribute.annotation.*;
026: import proguard.classfile.attribute.annotation.visitor.*;
027: import proguard.classfile.attribute.visitor.*;
028: import proguard.classfile.constant.*;
029: import proguard.classfile.constant.visitor.ConstantVisitor;
030: import proguard.classfile.editor.ClassReferenceFixer;
031: import proguard.classfile.util.SimplifiedVisitor;
032: import proguard.classfile.visitor.*;
033: import proguard.optimize.info.SingleImplementationMarker;
034:
035: /**
036: * This ClassVisitor replaces all references to interfaces that have single
037: * implementations by references to those implementations. The names will then
038: * have to be fixed, based on the new references.
039: *
040: * @see SingleImplementationMarker
041: * @see SingleImplementationFixer
042: * @see ClassReferenceFixer
043: * @author Eric Lafortune
044: */
045: public class SingleImplementationInliner extends SimplifiedVisitor
046: implements ClassVisitor, ConstantVisitor, MemberVisitor,
047: AttributeVisitor, LocalVariableInfoVisitor,
048: LocalVariableTypeInfoVisitor, AnnotationVisitor,
049: ElementValueVisitor {
050: // Implementations for ClassVisitor.
051:
052: public void visitProgramClass(ProgramClass programClass) {
053: // Update the constant pool.
054: programClass.constantPoolEntriesAccept(this );
055:
056: // Update the class members.
057: programClass.fieldsAccept(this );
058: programClass.methodsAccept(this );
059:
060: // Update the attributes.
061: programClass.attributesAccept(this );
062: }
063:
064: // Implementations for ConstantVisitor.
065:
066: public void visitAnyConstant(Clazz clazz, Constant constant) {
067: }
068:
069: public void visitStringConstant(Clazz clazz,
070: StringConstant stringConstant) {
071: if (stringConstant.referencedMember == null) {
072: // Update the referenced class if it is an interface with a single
073: // implementation.
074: Clazz singleImplementationClass = SingleImplementationMarker
075: .singleImplementation(stringConstant.referencedClass);
076:
077: if (singleImplementationClass != null) {
078: stringConstant.referencedClass = singleImplementationClass;
079: }
080: }
081: }
082:
083: public void visitInterfaceMethodrefConstant(Clazz clazz,
084: InterfaceMethodrefConstant interfaceMethodrefConstant) {
085: // Update the referenced interface if it has a single implementation.
086: Clazz singleImplementationClass = SingleImplementationMarker
087: .singleImplementation(interfaceMethodrefConstant.referencedClass);
088:
089: if (singleImplementationClass != null) {
090: // We know the single implementation contains the method.
091: String name = interfaceMethodrefConstant.getName(clazz);
092: String type = interfaceMethodrefConstant.getType(clazz);
093:
094: interfaceMethodrefConstant.referencedClass = singleImplementationClass;
095: interfaceMethodrefConstant.referencedMember = singleImplementationClass
096: .findMethod(name, type);
097: }
098: }
099:
100: public void visitClassConstant(Clazz clazz,
101: ClassConstant classConstant) {
102: // Update the referenced class if it is an interface with a single
103: // implementation.
104: Clazz singleImplementationClass = SingleImplementationMarker
105: .singleImplementation(classConstant.referencedClass);
106:
107: if (singleImplementationClass != null) {
108: classConstant.referencedClass = singleImplementationClass;
109: }
110: }
111:
112: // Implementations for MemberVisitor.
113:
114: public void visitProgramField(ProgramClass programClass,
115: ProgramField programField) {
116: // Update the referenced class if the type is an interface with a
117: // single implementation.
118: Clazz singleImplementationClass = SingleImplementationMarker
119: .singleImplementation(programField.referencedClass);
120:
121: if (singleImplementationClass != null) {
122: programField.referencedClass = singleImplementationClass;
123: }
124:
125: // Update the attributes.
126: programField.attributesAccept(programClass, this );
127: }
128:
129: public void visitProgramMethod(ProgramClass programClass,
130: ProgramMethod programMethod) {
131: // Update the referenced classes if the descriptor contains
132: // interfaces with single implementations.
133: updateReferencedClasses(programMethod.referencedClasses);
134:
135: // Update the attributes.
136: programMethod.attributesAccept(programClass, this );
137: }
138:
139: // Implementations for AttributeVisitor.
140:
141: public void visitAnyAttribute(Clazz clazz, Attribute attribute) {
142: }
143:
144: public void visitCodeAttribute(Clazz clazz, Method method,
145: CodeAttribute codeAttribute) {
146: // Update the referenced classes of the local variables.
147: codeAttribute.attributesAccept(clazz, method, this );
148: }
149:
150: public void visitLocalVariableTableAttribute(Clazz clazz,
151: Method method, CodeAttribute codeAttribute,
152: LocalVariableTableAttribute localVariableTableAttribute) {
153: // Update the referenced classes of the local variables.
154: localVariableTableAttribute.localVariablesAccept(clazz, method,
155: codeAttribute, this );
156: }
157:
158: public void visitLocalVariableTypeTableAttribute(
159: Clazz clazz,
160: Method method,
161: CodeAttribute codeAttribute,
162: LocalVariableTypeTableAttribute localVariableTypeTableAttribute) {
163: // Update the referenced classes of the local variable types.
164: localVariableTypeTableAttribute.localVariablesAccept(clazz,
165: method, codeAttribute, this );
166: }
167:
168: public void visitSignatureAttribute(Clazz clazz,
169: SignatureAttribute signatureAttribute) {
170: // Update the referenced classes.
171: updateReferencedClasses(signatureAttribute.referencedClasses);
172: }
173:
174: public void visitAnyAnnotationsAttribute(Clazz clazz,
175: AnnotationsAttribute annotationsAttribute) {
176: // Update the annotations.
177: annotationsAttribute.annotationsAccept(clazz, this );
178: }
179:
180: public void visitAnyParameterAnnotationsAttribute(Clazz clazz,
181: Method method,
182: ParameterAnnotationsAttribute parameterAnnotationsAttribute) {
183: // Update the annotations.
184: parameterAnnotationsAttribute.annotationsAccept(clazz, method,
185: this );
186: }
187:
188: public void visitAnnotationDefaultAttribute(Clazz clazz,
189: Method method,
190: AnnotationDefaultAttribute annotationDefaultAttribute) {
191: // Update the annotation.
192: annotationDefaultAttribute.defaultValueAccept(clazz, this );
193: }
194:
195: // Implementations for LocalVariableInfoVisitor.
196:
197: public void visitLocalVariableInfo(Clazz clazz, Method method,
198: CodeAttribute codeAttribute,
199: LocalVariableInfo localVariableInfo) {
200: // Update the referenced class if it is an interface with a single
201: // implementation.
202: Clazz singleImplementationClass = SingleImplementationMarker
203: .singleImplementation(localVariableInfo.referencedClass);
204:
205: if (singleImplementationClass != null) {
206: localVariableInfo.referencedClass = singleImplementationClass;
207: }
208: }
209:
210: // Implementations for LocalVariableTypeInfoVisitor.
211:
212: public void visitLocalVariableTypeInfo(Clazz clazz, Method method,
213: CodeAttribute codeAttribute,
214: LocalVariableTypeInfo localVariableTypeInfo) {
215: // Update the referenced classes.
216: updateReferencedClasses(localVariableTypeInfo.referencedClasses);
217: }
218:
219: // Implementations for AnnotationVisitor.
220:
221: public void visitAnnotation(Clazz clazz, Annotation annotation) {
222: // Update the referenced classes.
223: updateReferencedClasses(annotation.referencedClasses);
224:
225: // Update the element values.
226: annotation.elementValuesAccept(clazz, this );
227: }
228:
229: // Implementations for ElementValueVisitor.
230:
231: public void visitConstantElementValue(Clazz clazz,
232: Annotation annotation,
233: ConstantElementValue constantElementValue) {
234: }
235:
236: public void visitEnumConstantElementValue(Clazz clazz,
237: Annotation annotation,
238: EnumConstantElementValue enumConstantElementValue) {
239: // Update the referenced classes.
240: updateReferencedClasses(enumConstantElementValue.referencedClasses);
241: }
242:
243: public void visitClassElementValue(Clazz clazz,
244: Annotation annotation, ClassElementValue classElementValue) {
245: // Update the referenced classes.
246: updateReferencedClasses(classElementValue.referencedClasses);
247: }
248:
249: public void visitAnnotationElementValue(Clazz clazz,
250: Annotation annotation,
251: AnnotationElementValue annotationElementValue) {
252: // Update the annotation.
253: annotationElementValue.annotationAccept(clazz, this );
254: }
255:
256: public void visitArrayElementValue(Clazz clazz,
257: Annotation annotation, ArrayElementValue arrayElementValue) {
258: // Update the element values.
259: arrayElementValue.elementValuesAccept(clazz, annotation, this );
260: }
261:
262: // Small utility methods.
263:
264: /**
265: * Updates the given array of referenced classes, replacing references
266: * to a interfaces with single implementations by these implementations.
267: */
268: private void updateReferencedClasses(Clazz[] referencedClasses) {
269: // Update all referenced classes.
270: if (referencedClasses != null) {
271: for (int index = 0; index < referencedClasses.length; index++) {
272: // See if we have is an interface with a single implementation.
273: Clazz singleImplementationClass = SingleImplementationMarker
274: .singleImplementation(referencedClasses[index]);
275:
276: // Update or copy the referenced class.
277: if (singleImplementationClass != null) {
278: referencedClasses[index] = singleImplementationClass;
279: }
280: }
281: }
282: }
283: }
|