~ubuntu-branches/ubuntu/maverick/proguard/maverick

« back to all changes in this revision

Viewing changes to src/proguard/shrink/UsageMarker.java

  • Committer: Bazaar Package Importer
  • Author(s): Sam Clegg
  • Date: 2005-11-13 09:42:59 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20051113094259-432zf4yyw4890mmn
Tags: 3.4-1
* New upstream release (Closes: #338355)
* debian/control: bump standards version
* debian/copyright: update FSF address
* increase java stack size for proguard and proguardgui

Show diffs side-by-side

added added

removed removed

Lines of Context:
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 $
2
2
 *
3
3
 * ProGuard -- shrinking, optimization, and obfuscation of Java class files.
4
4
 *
5
 
 * Copyright (c) 2002-2004 Eric Lafortune (eric@graphics.cornell.edu)
 
5
 * Copyright (c) 2002-2005 Eric Lafortune (eric@graphics.cornell.edu)
6
6
 *
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
55
55
    private static final Object USED          = new Object();
56
56
 
57
57
 
58
 
    private MyInterfaceUsageMarker interfaceUsageMarker = new MyInterfaceUsageMarker();
 
58
    private MyInterfaceUsageMarker          interfaceUsageMarker          = new MyInterfaceUsageMarker();
 
59
    private MyPossiblyUsedMethodUsageMarker possiblyUsedMethodUsageMarker = new MyPossiblyUsedMethodUsageMarker();
59
60
//    private ClassFileVisitor       dynamicClassMarker   =
60
61
//        new MultiClassFileVisitor(
61
62
//        new ClassFileVisitor[]
66
67
//                                   this)
67
68
//        });
68
69
 
69
 
    
70
 
    // A field acting as a parameter to the visitMemberInfo method.
71
 
    private boolean processing = false;
72
 
 
73
70
 
74
71
    // Implementations for ClassFileVisitor.
75
72
 
76
73
    public void visitProgramClassFile(ProgramClassFile programClassFile)
77
74
    {
78
 
        if (!isUsed(programClassFile))
 
75
        if (shouldBeMarkedAsUsed(programClassFile))
79
76
        {
80
77
            // Mark this class.
81
78
            markAsUsed(programClassFile);
82
79
 
83
 
            // Mark this class's name.
84
 
            markCpEntry(programClassFile, programClassFile.u2thisClass);
85
 
 
86
 
            // Mark the superclass.
87
 
            if (programClassFile.u2superClass != 0)
88
 
            {
89
 
                markCpEntry(programClassFile, programClassFile.u2superClass);
90
 
            }
91
 
 
92
 
            // Give the interfaces preliminary marks.
93
 
            programClassFile.hierarchyAccept(false, false, true, false,
94
 
                                             interfaceUsageMarker);
95
 
 
96
 
            // Explicitly mark the <clinit> method.
97
 
            programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
98
 
                                          ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
99
 
                                          this);
100
 
 
101
 
            // Explicitly mark the parameterless <init> method.
102
 
            programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
103
 
                                          ClassConstants.INTERNAL_METHOD_TYPE_INIT,
104
 
                                          this);
105
 
 
106
 
            // Process all methods that have already been marked as possibly used.
107
 
            processing = true;
108
 
            programClassFile.methodsAccept(this);
109
 
            processing = false;
110
 
 
111
 
            // Mark the attributes.
112
 
            programClassFile.attributesAccept(this);
113
 
        }
 
80
            markProgramClassBody(programClassFile);
 
81
        }
 
82
    }
 
83
 
 
84
 
 
85
    protected void markProgramClassBody(ProgramClassFile programClassFile)
 
86
    {
 
87
        // Mark this class's name.
 
88
        markCpEntry(programClassFile, programClassFile.u2thisClass);
 
89
 
 
90
        // Mark the superclass.
 
91
        if (programClassFile.u2superClass != 0)
 
92
        {
 
93
            markCpEntry(programClassFile, programClassFile.u2superClass);
 
94
        }
 
95
 
 
96
        // Give the interfaces preliminary marks.
 
97
        programClassFile.hierarchyAccept(false, false, true, false,
 
98
                                         interfaceUsageMarker);
 
99
 
 
100
        // Explicitly mark the <clinit> method.
 
101
        programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_CLINIT,
 
102
                                      ClassConstants.INTERNAL_METHOD_TYPE_CLINIT,
 
103
                                      this);
 
104
 
 
105
        // Explicitly mark the parameterless <init> method.
 
106
        programClassFile.methodAccept(ClassConstants.INTERNAL_METHOD_NAME_INIT,
 
107
                                      ClassConstants.INTERNAL_METHOD_TYPE_INIT,
 
108
                                      this);
 
109
 
 
110
        // Process all methods that have already been marked as possibly used.
 
111
        programClassFile.methodsAccept(possiblyUsedMethodUsageMarker);
 
112
 
 
113
        // Mark the attributes.
 
114
        programClassFile.attributesAccept(this);
114
115
    }
115
116
 
116
117
 
117
118
    public void visitLibraryClassFile(LibraryClassFile libraryClassFile)
118
119
    {
119
 
        if (!isUsed(libraryClassFile))
 
120
        if (shouldBeMarkedAsUsed(libraryClassFile))
120
121
        {
121
122
            markAsUsed(libraryClassFile);
122
123
 
158
159
    {
159
160
        public void visitProgramClassFile(ProgramClassFile programClassFile)
160
161
        {
161
 
            if (!isUsed(programClassFile))
 
162
            if (shouldBeMarkedAsPossiblyUsed(programClassFile))
162
163
            {
163
164
                // We can't process the interface yet, because it might not
164
165
                // be required. Give it a preliminary mark.
174
175
    }
175
176
 
176
177
 
 
178
    private class MyPossiblyUsedMethodUsageMarker implements MemberInfoVisitor
 
179
    {
 
180
        // Implementations for MemberInfoVisitor.
 
181
    
 
182
        public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo) {}
 
183
    
 
184
    
 
185
        public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
 
186
        {
 
187
            // Has the method already been referenced?
 
188
            if (isPossiblyUsed(programMethodInfo))
 
189
            {
 
190
                markAsUsed(programMethodInfo);
 
191
 
 
192
                // Mark the method body.
 
193
                markProgramMethodBody(programClassFile, programMethodInfo);
 
194
                
 
195
                // Note that, if the method has been marked as possibly used,
 
196
                // the method hierarchy has already been marked (cfr. below).
 
197
            }
 
198
        }
 
199
    
 
200
    
 
201
        public void visitLibraryFieldInfo(LibraryClassFile libraryClassFile, LibraryFieldInfo libraryFieldInfo) {}
 
202
        public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo) {}
 
203
    }
 
204
 
 
205
    
177
206
    // Implementations for MemberInfoVisitor.
178
207
 
179
208
    public void visitProgramFieldInfo(ProgramClassFile programClassFile, ProgramFieldInfo programFieldInfo)
180
209
    {
181
 
        if (!isUsed(programFieldInfo))
 
210
        if (shouldBeMarkedAsUsed(programFieldInfo))
182
211
        {
183
212
            markAsUsed(programFieldInfo);
184
213
 
197
226
 
198
227
    public void visitProgramMethodInfo(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
199
228
    {
200
 
        if (!isUsed(programMethodInfo))
 
229
        if (shouldBeMarkedAsUsed(programMethodInfo))
201
230
        {
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))
205
233
            {
206
234
                markAsUsed(programMethodInfo);
207
235
 
208
 
                // Remember the processing flag.
209
 
                boolean oldProcessing = processing;
210
 
                processing = false;
211
 
 
212
 
                // Mark the name and descriptor.
213
 
                markCpEntry(programClassFile, programMethodInfo.u2nameIndex);
214
 
                markCpEntry(programClassFile, programMethodInfo.u2descriptorIndex);
215
 
 
216
 
                // Mark the attributes.
217
 
                programMethodInfo.attributesAccept(programClassFile, this);
218
 
 
219
 
                // Mark the classes referenced in the descriptor string.
220
 
                programMethodInfo.referencedClassesAccept(this);
221
 
 
222
 
                // Restore the processing flag.
223
 
                processing = oldProcessing;
224
 
 
225
 
                // If the method is being called, mark its hierarchy.
226
 
                if (!processing)
227
 
                {
228
 
                    markMethodHierarchy(programClassFile, programMethodInfo);
229
 
                }
 
236
                // Mark the method body.
 
237
                markProgramMethodBody(programClassFile, programMethodInfo);
 
238
 
 
239
                // Mark the method hierarchy.
 
240
                markMethodHierarchy(programClassFile, programMethodInfo);
230
241
            }
231
 
            else if (!processing && !isPossiblyUsed(programMethodInfo))
 
242
            
 
243
            // Hasn't the method been marked as possibly being used yet?
 
244
            else if (shouldBeMarkedAsPossiblyUsed(programMethodInfo))
232
245
            {
233
 
                // We can't process the class member yet, because the class
234
 
                // file isn't marked as being used (yet). Give it a
235
 
                // preliminary mark.
 
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);
237
249
 
238
 
                // The method is being called. Mark its hierarchy.
 
250
                // Mark the method hierarchy.
239
251
                markMethodHierarchy(programClassFile, programMethodInfo);
240
252
            }
241
253
        }
246
258
 
247
259
    public void visitLibraryMethodInfo(LibraryClassFile libraryClassFile, LibraryMethodInfo libraryMethodInfo)
248
260
    {
249
 
        if (!isUsed(libraryMethodInfo))
 
261
        if (shouldBeMarkedAsUsed(libraryMethodInfo))
250
262
        {
251
263
            markAsUsed(libraryMethodInfo);
252
 
            
 
264
 
 
265
            // Mark the method hierarchy.
253
266
            markMethodHierarchy(libraryClassFile, libraryMethodInfo);
254
267
        }
255
268
    }
256
269
 
257
270
 
258
 
    private void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
259
 
    {
260
 
        if ((methodInfo.getAccessFlags() &
261
 
             (ClassConstants.INTERNAL_ACC_PRIVATE |
262
 
              ClassConstants.INTERNAL_ACC_FINAL)) == 0)
263
 
        {
264
 
            String name = methodInfo.getName(classFile);
265
 
            String type = methodInfo.getDescriptor(classFile);
266
 
 
267
 
            if (!name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT) &&
268
 
                !name.equals(ClassConstants.INTERNAL_METHOD_NAME_CLINIT))
269
 
            {
270
 
                // Mark all implementations of the method.
271
 
                //
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
276
 
                //   the method.
277
 
                //
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.
281
 
                //
282
 
                // For a concrete method:
283
 
                //   Simply mark all overriding implementations down the
284
 
                //   class hierarchy.
285
 
                classFile.accept(
286
 
                    (classFile.getAccessFlags()  & ClassConstants.INTERNAL_ACC_INTERFACE) != 0 ||
287
 
                    (methodInfo.getAccessFlags() & ClassConstants.INTERNAL_ACC_ABSTRACT)  != 0 ?
288
 
    
289
 
                        (ClassFileVisitor)
290
 
                        new ConcreteClassFileDownTraveler(
291
 
                        new ClassFileHierarchyTraveler(true, true, false, true,
292
 
                        new NamedMethodVisitor(name, type,
293
 
                        new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this)))) :
294
 
    
295
 
                        (ClassFileVisitor)
296
 
                        new ClassFileHierarchyTraveler(false, false, false, true,
297
 
                        new NamedMethodVisitor(name, type,
298
 
                        new MemberInfoAccessFilter(0, ClassConstants.INTERNAL_ACC_PRIVATE, this))));
299
 
            }
300
 
        }
 
271
    protected void markProgramMethodBody(ProgramClassFile programClassFile, ProgramMethodInfo programMethodInfo)
 
272
    {
 
273
        // Mark the name and descriptor.
 
274
        markCpEntry(programClassFile, programMethodInfo.u2nameIndex);
 
275
        markCpEntry(programClassFile, programMethodInfo.u2descriptorIndex);
 
276
 
 
277
        // Mark the attributes.
 
278
        programMethodInfo.attributesAccept(programClassFile, this);
 
279
 
 
280
        // Mark the classes referenced in the descriptor string.
 
281
        programMethodInfo.referencedClassesAccept(this);
 
282
    }
 
283
 
 
284
 
 
285
    /**
 
286
     * Marks the hierarchy of implementing or overriding methods corresponding
 
287
     * to the given method, if any.
 
288
     */
 
289
    protected void markMethodHierarchy(ClassFile classFile, MethodInfo methodInfo)
 
290
    {
 
291
        classFile.methodImplementationsAccept(methodInfo, false, this);
301
292
    }
302
293
 
303
294
 
305
296
 
306
297
    public void visitIntegerCpInfo(ClassFile classFile, IntegerCpInfo integerCpInfo)
307
298
    {
308
 
        if (!isUsed(integerCpInfo))
 
299
        if (shouldBeMarkedAsUsed(integerCpInfo))
309
300
        {
310
301
            markAsUsed(integerCpInfo);
311
302
        }
314
305
 
315
306
    public void visitLongCpInfo(ClassFile classFile, LongCpInfo longCpInfo)
316
307
    {
317
 
        if (!isUsed(longCpInfo))
 
308
        if (shouldBeMarkedAsUsed(longCpInfo))
318
309
        {
319
310
            markAsUsed(longCpInfo);
320
311
        }
323
314
 
324
315
    public void visitFloatCpInfo(ClassFile classFile, FloatCpInfo floatCpInfo)
325
316
    {
326
 
        if (!isUsed(floatCpInfo))
 
317
        if (shouldBeMarkedAsUsed(floatCpInfo))
327
318
        {
328
319
            markAsUsed(floatCpInfo);
329
320
        }
332
323
 
333
324
    public void visitDoubleCpInfo(ClassFile classFile, DoubleCpInfo doubleCpInfo)
334
325
    {
335
 
        if (!isUsed(doubleCpInfo))
 
326
        if (shouldBeMarkedAsUsed(doubleCpInfo))
336
327
        {
337
328
            markAsUsed(doubleCpInfo);
338
329
        }
341
332
 
342
333
    public void visitStringCpInfo(ClassFile classFile, StringCpInfo stringCpInfo)
343
334
    {
344
 
        if (!isUsed(stringCpInfo))
 
335
        if (shouldBeMarkedAsUsed(stringCpInfo))
345
336
        {
346
337
            markAsUsed(stringCpInfo);
347
338
 
359
350
 
360
351
    public void visitUtf8CpInfo(ClassFile classFile, Utf8CpInfo utf8CpInfo)
361
352
    {
362
 
        if (!isUsed(utf8CpInfo))
 
353
        if (shouldBeMarkedAsUsed(utf8CpInfo))
363
354
        {
364
355
            markAsUsed(utf8CpInfo);
365
356
        }
386
377
 
387
378
    private void visitRefCpInfo(ClassFile classFile, RefCpInfo methodrefCpInfo)
388
379
    {
389
 
        if (!isUsed(methodrefCpInfo))
 
380
        if (shouldBeMarkedAsUsed(methodrefCpInfo))
390
381
        {
391
382
            markAsUsed(methodrefCpInfo);
392
383
 
407
398
 
408
399
    public void visitClassCpInfo(ClassFile classFile, ClassCpInfo classCpInfo)
409
400
    {
410
 
        if (!isUsed(classCpInfo))
 
401
        if (shouldBeMarkedAsUsed(classCpInfo))
411
402
        {
412
403
            markAsUsed(classCpInfo);
413
404
 
421
412
 
422
413
    public void visitNameAndTypeCpInfo(ClassFile classFile, NameAndTypeCpInfo nameAndTypeCpInfo)
423
414
    {
424
 
        if (!isUsed(nameAndTypeCpInfo))
 
415
        if (shouldBeMarkedAsUsed(nameAndTypeCpInfo))
425
416
        {
426
417
            markAsUsed(nameAndTypeCpInfo);
427
418
 
428
419
            markCpEntry(classFile, nameAndTypeCpInfo.u2nameIndex);
429
420
            markCpEntry(classFile, nameAndTypeCpInfo.u2descriptorIndex);
430
 
 
431
 
            // Mark the classes referenced in the descriptor string.
432
 
            nameAndTypeCpInfo.referencedClassesAccept(this);
433
421
        }
434
422
    }
435
423
 
451
439
    {
452
440
        // Don't mark the attribute and its name yet. We may mark it later, in
453
441
        // InnerUsageMarker.
454
 
        //markAsUsed(innerClassesAttrInfo);
 
442
        //_markAsUsed(innerClassesAttrInfo);
455
443
 
456
444
        //markCpEntry(classFile, innerClassesAttrInfo.u2attrNameIndex);
457
445
        innerClassesAttrInfo.innerClassEntriesAccept(classFile, this);
784
772
    // Small utility methods.
785
773
 
786
774
    /**
 
775
     * Marks the given visitor accepter as being used.
 
776
     */
 
777
    protected void markAsUsed(VisitorAccepter visitorAccepter)
 
778
    {
 
779
        visitorAccepter.setVisitorInfo(USED);
 
780
    }
 
781
 
 
782
 
 
783
    /**
 
784
     * Returns whether the given visitor accepter should still be marked as
 
785
     * being used.
 
786
     */
 
787
    protected boolean shouldBeMarkedAsUsed(VisitorAccepter visitorAccepter)
 
788
    {
 
789
        return visitorAccepter.getVisitorInfo() != USED;
 
790
    }
 
791
 
 
792
 
 
793
    /**
 
794
     * Returns whether the given visitor accepter has been marked as being used.
 
795
     */
 
796
    protected boolean isUsed(VisitorAccepter visitorAccepter)
 
797
    {
 
798
        return visitorAccepter.getVisitorInfo() == USED;
 
799
    }
 
800
 
 
801
 
 
802
    /**
 
803
     * Marks the given visitor accepter as possibly being used.
 
804
     */
 
805
    protected void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
 
806
    {
 
807
        visitorAccepter.setVisitorInfo(POSSIBLY_USED);
 
808
    }
 
809
 
 
810
 
 
811
    /**
 
812
     * Returns whether the given visitor accepter should still be marked as
 
813
     * possibly being used.
 
814
     */
 
815
    protected boolean shouldBeMarkedAsPossiblyUsed(VisitorAccepter visitorAccepter)
 
816
    {
 
817
        return visitorAccepter.getVisitorInfo() != USED &&
 
818
               visitorAccepter.getVisitorInfo() != POSSIBLY_USED;
 
819
    }
 
820
 
 
821
 
 
822
    /**
 
823
     * Returns whether the given visitor accepter has been marked as possibly
 
824
     * being used.
 
825
     */
 
826
    protected boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
 
827
    {
 
828
        return visitorAccepter.getVisitorInfo() == POSSIBLY_USED;
 
829
    }
 
830
 
 
831
 
 
832
    /**
 
833
     * Clears any usage marks from the given visitor accepter.
 
834
     */
 
835
    protected void markAsUnused(VisitorAccepter visitorAccepter)
 
836
    {
 
837
        visitorAccepter.setVisitorInfo(null);
 
838
    }
 
839
 
 
840
 
 
841
    /**
787
842
     * Marks the given constant pool entry of the given class. This includes
788
843
     * visiting any referenced objects.
789
844
     */
791
846
    {
792
847
         classFile.constantPoolEntryAccept(index, this);
793
848
    }
794
 
 
795
 
 
796
 
    static void markAsUnused(VisitorAccepter visitorAccepter)
797
 
    {
798
 
        visitorAccepter.setVisitorInfo(null);
799
 
    }
800
 
 
801
 
 
802
 
    static void markAsPossiblyUsed(VisitorAccepter visitorAccepter)
803
 
    {
804
 
        visitorAccepter.setVisitorInfo(POSSIBLY_USED);
805
 
    }
806
 
 
807
 
 
808
 
    static boolean isPossiblyUsed(VisitorAccepter visitorAccepter)
809
 
    {
810
 
        return visitorAccepter.getVisitorInfo() == POSSIBLY_USED;
811
 
    }
812
 
 
813
 
 
814
 
    static void markAsUsed(VisitorAccepter visitorAccepter)
815
 
    {
816
 
        visitorAccepter.setVisitorInfo(USED);
817
 
    }
818
 
 
819
 
 
820
 
    static boolean isUsed(VisitorAccepter visitorAccepter)
821
 
    {
822
 
        return visitorAccepter.getVisitorInfo() == USED;
823
 
    }
824
849
}