KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > optimize > info > SingleImplementationMarker


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.optimize.info;
22
23 import proguard.classfile.*;
24 import proguard.classfile.util.*;
25 import proguard.classfile.visitor.*;
26 import proguard.optimize.KeepMarker;
27
28 /**
29  * This ClassVisitor investigates all classes that it visits to see whether
30  * they have/are the sole (non-abstract) implementation of an interface.
31  * It may already modify the access of the single implementing class to match
32  * the access of the interface.
33  *
34  * @author Eric Lafortune
35  */

36 public class SingleImplementationMarker
37 extends SimplifiedVisitor
38 implements ClassVisitor
39 {
40     private static final boolean DEBUG = false;
41
42
43     private boolean allowAccessModification;
44     private ClassVisitor extraClassVisitor;
45
46
47     /**
48      * Creates a new SingleImplementationMarker.
49      * @param allowAccessModification indicates whether the access modifiers of
50      * a class can be changed in order to inline
51      * it.
52      */

53     public SingleImplementationMarker(boolean allowAccessModification)
54     {
55         this(allowAccessModification, null);
56     }
57
58
59     /**
60      * Creates a new SingleImplementationMarker.
61      * @param allowAccessModification indicates whether the access modifiers of
62      * a class can be changed in order to inline
63      * it.
64      * @param extraClassVisitor an optional extra visitor for all inlinable
65      * interfaces.
66      */

67     public SingleImplementationMarker(boolean allowAccessModification,
68                                       ClassVisitor extraClassVisitor)
69     {
70         this.allowAccessModification = allowAccessModification;
71         this.extraClassVisitor = extraClassVisitor;
72     }
73
74
75     // Implementations for ClassVisitor.
76

77     public void visitProgramClass(ProgramClass programClass)
78     {
79         // The program class must be an interface class that cannot be
80
// implemented again.
81
if ((programClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) == 0 ||
82             KeepMarker.isKept(programClass))
83         {
84             return;
85         }
86
87         // The interface class must have a single implementation.
88
Clazz[] subClasses = programClass.subClasses;
89         if (subClasses == null ||
90             subClasses.length != 1)
91         {
92             return;
93         }
94
95         // If the single implementation is an interface, check it recursively.
96
Clazz singleImplementationClass = subClasses[0];
97         int singleImplementationAccessFlags = singleImplementationClass.getAccessFlags();
98         if ((singleImplementationAccessFlags & ClassConstants.INTERNAL_ACC_INTERFACE) != 0)
99         {
100             singleImplementationClass.accept(this);
101
102             // See if the subinterface has a single implementation.
103
singleImplementationClass = singleImplementation(singleImplementationClass);
104             if (singleImplementationClass == null)
105             {
106                 return;
107             }
108
109             singleImplementationAccessFlags = singleImplementationClass.getAccessFlags();
110         }
111
112         // The single implementation must contain all non-static methods of this
113
// interface, so invocations can easily be diverted.
114
for (int index = 0; index < programClass.u2methodsCount; index++)
115         {
116             Method method = programClass.methods[index];
117             if ((method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) == 0 &&
118                 singleImplementationClass.findMethod(method.getName(programClass),
119                                                      method.getDescriptor(programClass)) == null)
120             {
121                 return;
122             }
123         }
124
125         // Doesn't the implementation have at least the same access as the
126
// interface?
127
if (AccessUtil.accessLevel(singleImplementationAccessFlags) <
128             AccessUtil.accessLevel(programClass.getAccessFlags()))
129         {
130             // Are we allowed to fix the access?
131
if (allowAccessModification)
132             {
133                 // Fix the access.
134
((ProgramClass)singleImplementationClass).u2accessFlags =
135                     AccessUtil.replaceAccessFlags(singleImplementationAccessFlags,
136                                                   programClass.getAccessFlags());
137             }
138             else
139             {
140                 // We can't give the implementation the access of the interface.
141
// Forget about inlining it after all.
142
return;
143             }
144         }
145
146         if (DEBUG)
147         {
148             System.out.println("Single implementation of ["+programClass.getName()+"]: ["+singleImplementationClass.getName()+"]");
149         }
150
151         // Mark the interface and its single implementation.
152
markSingleImplementation(programClass, singleImplementationClass);
153
154         // Visit the interface, if required.
155
if (extraClassVisitor != null)
156         {
157             singleImplementationClass.accept(extraClassVisitor);
158         }
159     }
160
161
162     // Small utility methods.
163

164     public static void markSingleImplementation(VisitorAccepter visitorAccepter,
165                                                 Clazz singleImplementation)
166     {
167         // The interface has a single implementation.
168
visitorAccepter.setVisitorInfo(singleImplementation);
169     }
170
171
172     public static Clazz singleImplementation(VisitorAccepter visitorAccepter)
173     {
174         return visitorAccepter != null &&
175                visitorAccepter.getVisitorInfo() instanceof Clazz ?
176                    (Clazz)visitorAccepter.getVisitorInfo() :
177                    null;
178     }
179 }
180
Popular Tags