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.constant.*;
025: import proguard.classfile.constant.visitor.ConstantVisitor;
026: import proguard.classfile.editor.*;
027: import proguard.classfile.util.SimplifiedVisitor;
028: import proguard.classfile.visitor.ClassVisitor;
029: import proguard.optimize.info.SingleImplementationMarker;
030:
031: /**
032: * This ClassVisitor cleans up after the SingleImplementationInliner.
033: * It fixes the names of interfaces that have single implementations, lets
034: * the implementations and fields references point to them again. This is
035: * necessary after the SingleImplementationInliner has overzealously renamed
036: * the interfaces to the single implementations, let the single implementations
037: * point to themselves as interfaces, and let the field references point to the
038: * single implementations.
039: *
040: * @see SingleImplementationInliner
041: * @see ClassReferenceFixer
042: * @author Eric Lafortune
043: */
044: public class SingleImplementationFixer extends SimplifiedVisitor
045: implements ClassVisitor, ConstantVisitor {
046: private final ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor();
047:
048: // Implementations for ClassVisitor.
049:
050: public void visitProgramClass(ProgramClass programClass) {
051: // Is this an interface with a single implementation?
052: Clazz singleImplementationClass = SingleImplementationMarker
053: .singleImplementation(programClass);
054:
055: if (singleImplementationClass != null) {
056: // Fix the reference to its own name.
057: fixThisClassReference(programClass);
058:
059: // Fix the reference from its single interface or implementation.
060: fixInterfaceReference(
061: (ProgramClass) programClass.subClasses[0],
062: programClass);
063: }
064:
065: // Fix the field references in the constant pool.
066: programClass.constantPoolEntriesAccept(this );
067: }
068:
069: // Implementations for ConstantVisitor.
070:
071: public void visitAnyConstant(Clazz clazz, Constant constant) {
072: }
073:
074: public void visitFieldrefConstant(Clazz clazz,
075: FieldrefConstant fieldrefConstant) {
076: // Update the referenced class if it is an interface with a single
077: // implementation.
078: Clazz singleImplementationClass = SingleImplementationMarker
079: .singleImplementation(fieldrefConstant.referencedClass);
080:
081: if (singleImplementationClass != null) {
082: // Fix the reference to the interface.
083: fixFieldrefClassReference((ProgramClass) clazz,
084: fieldrefConstant);
085: }
086: }
087:
088: // Small utility methods.
089:
090: /**
091: * Fixes the given class, so its name points to itself again.
092: */
093: private void fixThisClassReference(ProgramClass programClass) {
094: // We have to add a new class entry to avoid an existing entry with the
095: // same name being reused. The names have to be fixed later, based on
096: // their referenced classes.
097: int nameIndex = constantPoolEditor.addUtf8Constant(
098: programClass, programClass.getName());
099: programClass.u2this Class = constantPoolEditor.addConstant(
100: programClass,
101: new ClassConstant(nameIndex, programClass));
102: }
103:
104: /**
105: * Fixes the given class, so it points to the given interface again.
106: */
107: private void fixInterfaceReference(ProgramClass programClass,
108: ProgramClass interfaceClass) {
109: // Make sure the class refers to the given interface again.
110: String interfaceName = interfaceClass.getName();
111:
112: int interfacesCount = programClass.u2interfacesCount;
113: for (int index = 0; index < interfacesCount; index++) {
114: if (interfaceName.equals(programClass
115: .getInterfaceName(index))) {
116: // Update the class index.
117: // We have to add a new class entry to avoid an existing entry
118: // with the same name being reused. The names have to be fixed
119: // later, based on their referenced classes.
120: int nameIndex = constantPoolEditor.addUtf8Constant(
121: programClass, interfaceName);
122: programClass.u2interfaces[index] = constantPoolEditor
123: .addConstant(programClass, new ClassConstant(
124: nameIndex, interfaceClass));
125: break;
126:
127: }
128: }
129: }
130:
131: /**
132: * Fixes the given field reference, so its class index points to its
133: * class again. Note that this could be a different class than the one
134: * in the original class.
135: */
136: private void fixFieldrefClassReference(ProgramClass programClass,
137: FieldrefConstant fieldrefConstant) {
138: Clazz referencedClass = fieldrefConstant.referencedClass;
139:
140: // We have to add a new class entry to avoid an existing entry with the
141: // same name being reused. The names have to be fixed later, based on
142: // their referenced classes.
143: int nameIndex = constantPoolEditor.addUtf8Constant(
144: programClass, fieldrefConstant
145: .getClassName(programClass));
146: fieldrefConstant.u2classIndex = constantPoolEditor.addConstant(
147: programClass, new ClassConstant(nameIndex,
148: referencedClass));
149: }
150: }
|