1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 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