ShortestUsageMarker.java revision b72c5c2e5482cf10117b2b25f642f7616b2326c3
1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 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 */
21package proguard.shrink;
22
23import proguard.classfile.*;
24import proguard.classfile.visitor.*;
25
26
27/**
28 * This ClassVisitor and MemberVisitor recursively marks all classes
29 * and class elements that are being used. For each element, it finds the
30 * shortest chain of dependencies.
31 *
32 * @see ClassShrinker
33 *
34 * @author Eric Lafortune
35 */
36public class ShortestUsageMarker extends UsageMarker
37{
38    private static final ShortestUsageMark INITIAL_MARK =
39        new ShortestUsageMark("is kept by a directive in the configuration.\n\n");
40
41
42    // A field acting as a parameter to the visitor methods.
43    private ShortestUsageMark currentUsageMark = INITIAL_MARK;
44
45    // A utility object to check for recursive causes.
46    private final MyRecursiveCauseChecker recursiveCauseChecker = new MyRecursiveCauseChecker();
47
48
49    // Overriding implementations for UsageMarker.
50
51    protected void markProgramClassBody(ProgramClass programClass)
52    {
53        ShortestUsageMark previousUsageMark = currentUsageMark;
54
55        currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programClass),
56                                                 "is extended by   ",
57                                                 10000,
58                                                 programClass);
59
60        super.markProgramClassBody(programClass);
61
62        currentUsageMark = previousUsageMark;
63    }
64
65
66    protected void markProgramFieldBody(ProgramClass programClass, ProgramField programField)
67    {
68        ShortestUsageMark previousUsageMark = currentUsageMark;
69
70        currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programField),
71                                                 "is referenced by ",
72                                                 1,
73                                                 programClass,
74                                                 programField);
75
76        super.markProgramFieldBody(programClass, programField);
77
78        currentUsageMark = previousUsageMark;
79    }
80
81
82    protected void markProgramMethodBody(ProgramClass programClass, ProgramMethod programMethod)
83    {
84        ShortestUsageMark previousUsageMark = currentUsageMark;
85
86        currentUsageMark = new ShortestUsageMark(getShortestUsageMark(programMethod),
87                                                 "is invoked by    ",
88                                                 1,
89                                                 programClass,
90                                                 programMethod);
91
92        super.markProgramMethodBody(programClass, programMethod);
93
94        currentUsageMark = previousUsageMark;
95    }
96
97
98    protected void markMethodHierarchy(Clazz clazz, Method method)
99    {
100        ShortestUsageMark previousUsageMark = currentUsageMark;
101
102        currentUsageMark = new ShortestUsageMark(getShortestUsageMark(method),
103                                                 "implements       ",
104                                                 100,
105                                                 clazz,
106                                                 method);
107
108        super.markMethodHierarchy(clazz, method);
109
110        currentUsageMark = previousUsageMark;
111    }
112
113
114    // Small utility methods.
115
116    protected void markAsUsed(VisitorAccepter visitorAccepter)
117    {
118        Object visitorInfo = visitorAccepter.getVisitorInfo();
119
120        ShortestUsageMark shortestUsageMark =
121            visitorInfo != null                           &&
122            visitorInfo instanceof ShortestUsageMark      &&
123            !((ShortestUsageMark)visitorInfo).isCertain() &&
124            !currentUsageMark.isShorter((ShortestUsageMark)visitorInfo) ?
125                new ShortestUsageMark((ShortestUsageMark)visitorInfo, true):
126                currentUsageMark;
127
128        visitorAccepter.setVisitorInfo(shortestUsageMark);
129    }
130
131
132    protected boolean shouldBeMarkedAsUsed(VisitorAccepter visitorAccepter)
133    {
134        Object visitorInfo = visitorAccepter.getVisitorInfo();
135
136        return //!(visitorAccepter instanceof Clazz &&
137               //  isCausedBy(currentUsageMark, (Clazz)visitorAccepter)) &&
138               (visitorInfo == null                           ||
139               !(visitorInfo instanceof ShortestUsageMark)   ||
140               !((ShortestUsageMark)visitorInfo).isCertain() ||
141               currentUsageMark.isShorter((ShortestUsageMark)visitorInfo));
142    }
143
144
145    protected boolean isUsed(VisitorAccepter visitorAccepter)
146    {
147        Object visitorInfo = visitorAccepter.getVisitorInfo();
148
149        return visitorInfo != null                      &&
150               visitorInfo instanceof ShortestUsageMark &&
151               ((ShortestUsageMark)visitorInfo).isCertain();
152    }
153
154
155    protected void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
156    {
157        visitorAccepter.setVisitorInfo(new ShortestUsageMark(currentUsageMark, false));
158    }
159
160
161    protected boolean shouldBeMarkedAsPossiblyUsed(VisitorAccepter visitorAccepter)
162    {
163        Object visitorInfo = visitorAccepter.getVisitorInfo();
164
165        return visitorInfo == null                         ||
166               !(visitorInfo instanceof ShortestUsageMark) ||
167               (!((ShortestUsageMark)visitorInfo).isCertain() &&
168                currentUsageMark.isShorter((ShortestUsageMark)visitorInfo));
169    }
170
171
172    protected boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
173    {
174        Object visitorInfo = visitorAccepter.getVisitorInfo();
175
176        return visitorInfo != null                      &&
177               visitorInfo instanceof ShortestUsageMark &&
178               !((ShortestUsageMark)visitorInfo).isCertain();
179    }
180
181
182    protected ShortestUsageMark getShortestUsageMark(VisitorAccepter visitorAccepter)
183    {
184        Object visitorInfo = visitorAccepter.getVisitorInfo();
185
186        return (ShortestUsageMark)visitorInfo;
187    }
188
189
190    // Small utility methods.
191
192    private boolean isCausedBy(ShortestUsageMark shortestUsageMark,
193                               Clazz             clazz)
194    {
195        return recursiveCauseChecker.check(shortestUsageMark, clazz);
196    }
197
198
199    private class MyRecursiveCauseChecker implements ClassVisitor, MemberVisitor
200    {
201        private Clazz   checkClass;
202        private boolean isRecursing;
203
204
205        public boolean check(ShortestUsageMark shortestUsageMark,
206                             Clazz             clazz)
207        {
208            checkClass  = clazz;
209            isRecursing = false;
210
211            shortestUsageMark.acceptClassVisitor(this);
212            shortestUsageMark.acceptMemberVisitor(this);
213
214            return isRecursing;
215        }
216
217        // Implementations for ClassVisitor.
218
219        public void visitProgramClass(ProgramClass programClass)
220        {
221            checkCause(programClass);
222        }
223
224
225        public void visitLibraryClass(LibraryClass libraryClass)
226        {
227            checkCause(libraryClass);
228        }
229
230
231        // Implementations for MemberVisitor.
232
233        public void visitProgramField(ProgramClass programClass, ProgramField programField)
234        {
235            checkCause(programField);
236        }
237
238
239        public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
240        {
241            checkCause(programMethod);
242        }
243
244
245        public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField)
246        {
247             checkCause(libraryField);
248       }
249
250
251        public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod)
252        {
253            checkCause(libraryMethod);
254        }
255
256
257        // Small utility methods.
258
259        private void checkCause(VisitorAccepter visitorAccepter)
260        {
261            if (ShortestUsageMarker.this.isUsed(visitorAccepter))
262            {
263                ShortestUsageMark shortestUsageMark = ShortestUsageMarker.this.getShortestUsageMark(visitorAccepter);
264
265                // Check the class of this mark, if any
266                isRecursing = shortestUsageMark.isCausedBy(checkClass);
267
268                // Check the causing class or method, if still necessary.
269                if (!isRecursing)
270                {
271                    shortestUsageMark.acceptClassVisitor(this);
272                    shortestUsageMark.acceptMemberVisitor(this);
273                }
274            }
275        }
276    }
277}
278