| 1 21 package proguard.optimize; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.AttributeVisitor; 26 import proguard.classfile.attribute.annotation.*; 27 import proguard.classfile.editor.*; 28 import proguard.classfile.util.*; 29 import proguard.classfile.visitor.MemberVisitor; 30 import proguard.optimize.info.*; 31 import proguard.optimize.peephole.VariableShrinker; 32 33 42 public class MethodDescriptorShrinker 43 extends SimplifiedVisitor 44 implements MemberVisitor, 45 AttributeVisitor 46 { 47 private static final boolean DEBUG = false; 48 49 50 private MemberVisitor extraParameterMemberVisitor; 51 52 private ConstantPoolEditor constantPoolEditor = new ConstantPoolEditor(); 53 54 55 58 public MethodDescriptorShrinker() 59 { 60 this(null); 61 } 62 63 64 70 public MethodDescriptorShrinker(MemberVisitor extraParameterMemberVisitor) 71 { 72 this.extraParameterMemberVisitor = extraParameterMemberVisitor; 73 } 74 75 76 78 public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) 79 { 80 String descriptor = programMethod.getDescriptor(programClass); 82 String newDescriptor = shrinkDescriptor(programClass, programMethod); 83 if (!descriptor.equals(newDescriptor)) 84 { 85 programMethod.attributesAccept(programClass, this); 87 88 String name = programMethod.getName(programClass); 89 String newName; 90 91 if (name.equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) 93 { 94 if (programClass.findMethod(name, newDescriptor) != null) 96 { 97 ParameterUsageMarker.markUsedParameters(programMethod, -1L); 99 100 return; 101 } 102 103 newName = name; 105 } 106 else 107 { 108 newName = name + ClassConstants.SPECIAL_MEMBER_SEPARATOR + Long.toHexString(Math.abs((descriptor).hashCode())); 110 } 111 112 if (DEBUG) 113 { 114 System.out.println("MethodDescriptorShrinker:"); 115 System.out.println(" Class file = "+programClass.getName()); 116 System.out.println(" Method name = "+name); 117 System.out.println(" -> "+newName); 118 System.out.println(" Method descriptor = "+descriptor); 119 System.out.println(" -> "+newDescriptor); 120 } 121 122 if (!newName.equals(name)) 124 { 125 programMethod.u2nameIndex = 126 constantPoolEditor.addUtf8Constant(programClass, newName); 127 } 128 129 shrinkReferencedClasses(programClass, programMethod); 131 132 programMethod.u2descriptorIndex = 134 constantPoolEditor.addUtf8Constant(programClass, newDescriptor); 135 136 if (extraParameterMemberVisitor != null) 138 { 139 extraParameterMemberVisitor.visitProgramMethod(programClass, programMethod); 140 } 141 } 142 } 143 144 145 147 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 148 149 150 public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) 151 { 152 int[] annotationsCounts = parameterAnnotationsAttribute.u2parameterAnnotationsCount; 153 Annotation[][] annotations = parameterAnnotationsAttribute.parameterAnnotations; 154 155 int parameterIndex = 158 (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 159 0 : 1; 160 161 int annotationIndex = 0; 162 int newAnnotationIndex = 0; 163 164 String descriptor = method.getDescriptor(clazz); 166 InternalTypeEnumeration internalTypeEnumeration = 167 new InternalTypeEnumeration(descriptor); 168 169 while (internalTypeEnumeration.hasMoreTypes()) 170 { 171 String type = internalTypeEnumeration.nextType(); 172 if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) 173 { 174 annotationsCounts[newAnnotationIndex] = annotationsCounts[annotationIndex]; 175 annotations[newAnnotationIndex++] = annotations[annotationIndex]; 176 } 177 178 annotationIndex++; 179 180 parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; 181 } 182 183 parameterAnnotationsAttribute.u2parametersCount = newAnnotationIndex; 185 186 while (newAnnotationIndex < annotationIndex) 188 { 189 annotationsCounts[newAnnotationIndex] = 0; 190 annotations[newAnnotationIndex++] = null; 191 } 192 } 193 194 195 197 200 public static String shrinkDescriptor(ProgramClass clazz, 201 ProgramMethod method) 202 { 203 int parameterIndex = 206 (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 207 0 : 1; 208 209 InternalTypeEnumeration internalTypeEnumeration = 211 new InternalTypeEnumeration(method.getDescriptor(clazz)); 212 213 StringBuffer newDescriptorBuffer = new StringBuffer (); 214 newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_OPEN); 215 216 if (DEBUG) 217 { 218 System.out.println("MethodDescriptorShrinker: "+method.getName(clazz)+method.getDescriptor(clazz)); 219 System.out.println(" parameter size = " + ParameterUsageMarker.getParameterSize(method)); 220 } 221 222 while (internalTypeEnumeration.hasMoreTypes()) 223 { 224 String type = internalTypeEnumeration.nextType(); 225 if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) 226 { 227 newDescriptorBuffer.append(type); 228 } 229 else if (DEBUG) 230 { 231 System.out.println(" Deleting parameter #"+parameterIndex+" ("+type+")"); 232 } 233 234 parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; 235 } 236 237 newDescriptorBuffer.append(ClassConstants.INTERNAL_METHOD_ARGUMENTS_CLOSE); 238 newDescriptorBuffer.append(internalTypeEnumeration.returnType()); 239 240 return newDescriptorBuffer.toString(); 241 } 242 243 244 247 private static void shrinkReferencedClasses(ProgramClass clazz, 248 ProgramMethod method) 249 { 250 Clazz[] referencedClasses = method.referencedClasses; 251 252 if (referencedClasses != null) 253 { 254 int parameterIndex = 257 (method.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0 ? 258 0 : 1; 259 260 int referencedClassIndex = 0; 261 int newReferencedClassIndex = 0; 262 263 String descriptor = method.getDescriptor(clazz); 265 InternalTypeEnumeration internalTypeEnumeration = 266 new InternalTypeEnumeration(descriptor); 267 268 while (internalTypeEnumeration.hasMoreTypes()) 269 { 270 String type = internalTypeEnumeration.nextType(); 271 if (ClassUtil.isInternalArrayType(type)) 272 { 273 type = ClassUtil.internalTypeFromArrayType(type); 274 } 275 276 if (ClassUtil.isInternalClassType(type)) 277 { 278 if (ParameterUsageMarker.isParameterUsed(method, parameterIndex)) 279 { 280 referencedClasses[newReferencedClassIndex++] = 281 referencedClasses[referencedClassIndex]; 282 } 283 284 referencedClassIndex++; 285 } 286 287 parameterIndex += ClassUtil.isInternalCategory2Type(type) ? 2 : 1; 288 } 289 290 String type = internalTypeEnumeration.returnType(); 292 if (ClassUtil.isInternalArrayType(type)) 293 { 294 type = ClassUtil.internalTypeFromArrayType(type); 295 } 296 297 if (ClassUtil.isInternalClassType(type)) 298 { 299 referencedClasses[newReferencedClassIndex++] = 300 referencedClasses[referencedClassIndex]; 301 302 referencedClassIndex++; 303 } 304 305 while (newReferencedClassIndex < referencedClassIndex) 307 { 308 referencedClasses[newReferencedClassIndex++] = null; 309 } 310 } 311 } 312 } 313 | Popular Tags |