1
/* $Id: UsageMarker.java,v 1.37 2004/12/19 21:03:54 eric Exp $
1
/* $Id: UsageMarker.java,v 1.46 2005/06/26 16:19:24 eric Exp $
3
3
* ProGuard -- shrinking, optimization, and obfuscation of Java class files.
5
* Copyright (c) 2002-2004 Eric Lafortune (eric@graphics.cornell.edu)
5
* Copyright (c) 2002-2005 Eric Lafortune (eric@graphics.cornell.edu)
7
7
* This program is free software; you can redistribute it and/or modify it
8
8
* under the terms of the GNU General Public License as published by the Free
70
// A field acting as a parameter to the visitMemberInfo method.
71
private boolean processing = false;
74
71
// Implementations for ClassFileVisitor.
76
73
public void visitProgramClassFile(ProgramClassFile programClassFile)
78
if (!isUsed(programClassFile))
75
if (shouldBeMarkedAsUsed(programClassFile))
80
77
// Mark this class.
81
78
markAsUsed(programClassFile);
83
// Mark this class's name.
84
markCpEntry(programClassFile, programClassFile.u2thisClass);
86
// Mark the superclass.
87
if (programClassFile.u2superClass != 0)
89
markCpEntry(programClassFile, programClassFile.u2superClass);
92
// Give the interfaces preliminary marks.
93
programClassFile.hierarchyAccept(false, false, true, false,
94
interfaceUsageMarker);
96
// Explicitly mark the <clinit> method.
97
programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
98
ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
101
// Explicitly mark the parameterless <init> method.
102
programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
103
ClassConstants.INTERNAL_METHOD_TYPE_INIT,
106
// Process all methods that have already been marked as possibly used.
108
programClassFile.methodsAccept(this);
111
// Mark the attributes.
112
programClassFile.attributesAccept(this);
80
markProgramClassBody(programClassFile);
85
protected void markProgramClassBody(ProgramClassFile programClassFile)
87
// Mark this class's name.
88
markCpEntry(programClassFile, programClassFile.u2thisClass);
90
// Mark the superclass.
91
if (programClassFile.u2superClass != 0)
93
markCpEntry(programClassFile, programClassFile.u2superClass);
96
// Give the interfaces preliminary marks.
97
programClassFile.hierarchyAccept(false, false, true, false,
98
interfaceUsageMarker);
100
// Explicitly mark the <clinit> method.
101
programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
102
ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
105
// Explicitly mark the parameterless <init> method.
106
programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
107
ClassConstants.INTERNAL_METHOD_TYPE_INIT,
110
// Process all methods that have already been marked as possibly used.
111
programClassFile.methodsAccept(possiblyUsedMethodUsageMarker);
113
// Mark the attributes.
114
programClassFile.attributesAccept(this);
117
118
public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
119
if (!isUsed(libraryClassFile))
120
if (shouldBeMarkedAsUsed(libraryClassFile))
121
122
markAsUsed(libraryClassFile);
178
private class MyPossiblyUsedMethodUsageMarker implements MemberInfoVisitor
180
// Implementations for MemberInfoVisitor.
182
public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
185
public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
187
// Has the method already been referenced?
188
if (isPossiblyUsed(programMethodInfo))
190
markAsUsed(programMethodInfo);
192
// Mark the method body.
193
markProgramMethodBody(programClassFile, programMethodInfo);
195
// Note that, if the method has been marked as possibly used,
196
// the method hierarchy has already been marked (cfr. below).
201
public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
202
public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
177
206
// Implementations for MemberInfoVisitor.
179
208
public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
181
if (!isUsed(programFieldInfo))
210
if (shouldBeMarkedAsUsed(programFieldInfo))
183
212
markAsUsed(programFieldInfo);
198
227
public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
200
if (!isUsed(programMethodInfo))
229
if (shouldBeMarkedAsUsed(programMethodInfo))
202
// Are the method and its class used?
203
if (processing ? isPossiblyUsed(programMethodInfo) :
204
isUsed(programClassFile))
231
// Is the method's class used?
232
if (isUsed(programClassFile))
206
234
markAsUsed(programMethodInfo);
208
// Remember the processing flag.
209
boolean oldProcessing = processing;
212
// Mark the name and descriptor.
213
markCpEntry(programClassFile, programMethodInfo.u2nameIndex);
214
markCpEntry(programClassFile, programMethodInfo.u2descriptorIndex);
216
// Mark the attributes.
217
programMethodInfo.attributesAccept(programClassFile, this);
219
// Mark the classes referenced in the descriptor string.
220
programMethodInfo.referencedClassesAccept(this);
222
// Restore the processing flag.
223
processing = oldProcessing;
225
// If the method is being called, mark its hierarchy.
228
markMethodHierarchy(programClassFile, programMethodInfo);
236
// Mark the method body.
237
markProgramMethodBody(programClassFile, programMethodInfo);
239
// Mark the method hierarchy.
240
markMethodHierarchy(programClassFile, programMethodInfo);
231
else if (!processing && !isPossiblyUsed(programMethodInfo))
243
// Hasn't the method been marked as possibly being used yet?
244
else if (shouldBeMarkedAsPossiblyUsed(programMethodInfo))
233
// We can't process the class member yet, because the class
234
// file isn't marked as being used (yet). Give it a
246
// We can't process the method yet, because the class isn't
247
// marked as being used (yet). Give it a preliminary mark.
236
248
markAsPossiblyUsed(programMethodInfo);
238
// The method is being called. Mark its hierarchy.
250
// Mark the method hierarchy.
239
251
markMethodHierarchy(programClassFile, programMethodInfo);
247
259
public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
249
if (!isUsed(libraryMethodInfo))
261
if (shouldBeMarkedAsUsed(libraryMethodInfo))
251
263
markAsUsed(libraryMethodInfo);
265
// Mark the method hierarchy.
253
266
markMethodHierarchy(libraryClassFile, libraryMethodInfo);
258
private void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
260
if ((methodInfo.getAccessFlags() &
261
(ClassConstants.INTERNAL_ACC_PRIVATE |
262
ClassConstants.INTERNAL_ACC_FINAL)) == 0)
264
String name = methodInfo.getName(classFile);
265
String type = methodInfo.getDescriptor(classFile);
267
if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) &&
268
!name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT))
270
// Mark all implementations of the method.
272
// For an abstract method:
273
// First go to all concrete implementations or extensions of
274
// the interface or abstract class.
275
// From there, travel up and down the class hierarchy to mark
278
// This way, we're also catching retro-fitted interfaces,
279
// where a class's implementation of an interface method is
280
// hiding higher up its class hierarchy.
282
// For a concrete method:
283
// Simply mark all overriding implementations down the
286
(classFile.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0 ||
287
(methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT) != 0 ?
290
new ConcreteClassFileDownTraveler(
291
new ClassFileHierarchyTraveler(true, true, false, true,
292
new NamedMethodVisitor(name, type,
293
new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)))) :
296
new ClassFileHierarchyTraveler(false, false, false, true,
297
new NamedMethodVisitor(name, type,
298
new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))));
271
protected void markProgramMethodBody(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
273
// Mark the name and descriptor.
274
markCpEntry(programClassFile, programMethodInfo.u2nameIndex);
275
markCpEntry(programClassFile, programMethodInfo.u2descriptorIndex);
277
// Mark the attributes.
278
programMethodInfo.attributesAccept(programClassFile, this);
280
// Mark the classes referenced in the descriptor string.
281
programMethodInfo.referencedClassesAccept(this);
286
* Marks the hierarchy of implementing or overriding methods corresponding
287
* to the given method, if any.
289
protected void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
291
classFile.methodImplementationsAccept(methodInfo, false, this);
422
413
public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
424
if (!isUsed(nameAndTypeCpInfo))
415
if (shouldBeMarkedAsUsed(nameAndTypeCpInfo))
426
417
markAsUsed(nameAndTypeCpInfo);
428
419
markCpEntry(classFile, nameAndTypeCpInfo.u2nameIndex);
429
420
markCpEntry(classFile, nameAndTypeCpInfo.u2descriptorIndex);
431
// Mark the classes referenced in the descriptor string.
432
nameAndTypeCpInfo.referencedClassesAccept(this);
784
772
// Small utility methods.
775
* Marks the given visitor accepter as being used.
777
protected void markAsUsed(VisitorAccepter visitorAccepter)
779
visitorAccepter.setVisitorInfo(USED);
784
* Returns whether the given visitor accepter should still be marked as
787
protected boolean shouldBeMarkedAsUsed(VisitorAccepter visitorAccepter)
789
return visitorAccepter.getVisitorInfo() != USED;
794
* Returns whether the given visitor accepter has been marked as being used.
796
protected boolean isUsed(VisitorAccepter visitorAccepter)
798
return visitorAccepter.getVisitorInfo() == USED;
803
* Marks the given visitor accepter as possibly being used.
805
protected void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
807
visitorAccepter.setVisitorInfo(POSSIBLY_USED);
812
* Returns whether the given visitor accepter should still be marked as
813
* possibly being used.
815
protected boolean shouldBeMarkedAsPossiblyUsed(VisitorAccepter visitorAccepter)
817
return visitorAccepter.getVisitorInfo() != USED &&
818
visitorAccepter.getVisitorInfo() != POSSIBLY_USED;
823
* Returns whether the given visitor accepter has been marked as possibly
826
protected boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
828
return visitorAccepter.getVisitorInfo() == POSSIBLY_USED;
833
* Clears any usage marks from the given visitor accepter.
835
protected void markAsUnused(VisitorAccepter visitorAccepter)
837
visitorAccepter.setVisitorInfo(null);
787
842
* Marks the given constant pool entry of the given class. This includes
788
843
* visiting any referenced objects.
792
847
classFile.constantPoolEntryAccept(index, this);
796
static void markAsUnused(VisitorAccepter visitorAccepter)
798
visitorAccepter.setVisitorInfo(null);
802
static void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
804
visitorAccepter.setVisitorInfo(POSSIBLY_USED);
808
static boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
810
return visitorAccepter.getVisitorInfo() == POSSIBLY_USED;
814
static void markAsUsed(VisitorAccepter visitorAccepter)
816
visitorAccepter.setVisitorInfo(USED);
820
static boolean isUsed(VisitorAccepter visitorAccepter)
822
return visitorAccepter.getVisitorInfo() == USED;