Home | History | Annotate | Download | only in shrink
      1 /*
      2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
      3  *             of Java bytecode.
      4  *
      5  * Copyright (c) 2002-2009 Eric Lafortune (eric (at) 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.shrink;
     22 
     23 import proguard.classfile.*;
     24 import 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  */
     36 public 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