1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2013 Eric Lafortune (eric@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 */ 21package proguard.classfile.editor; 22 23import proguard.classfile.*; 24import proguard.classfile.attribute.*; 25import proguard.classfile.attribute.annotation.*; 26import proguard.classfile.attribute.annotation.visitor.*; 27import proguard.classfile.attribute.preverification.*; 28import proguard.classfile.attribute.preverification.visitor.*; 29import proguard.classfile.attribute.visitor.*; 30import proguard.classfile.constant.*; 31import proguard.classfile.constant.visitor.ConstantVisitor; 32import proguard.classfile.instruction.*; 33import proguard.classfile.instruction.visitor.InstructionVisitor; 34import proguard.classfile.util.SimplifiedVisitor; 35import proguard.classfile.visitor.*; 36 37import java.util.Arrays; 38 39/** 40 * This ClassVisitor removes all unused entries from the constant pool. 41 * 42 * @author Eric Lafortune 43 */ 44public class ConstantPoolShrinker 45extends SimplifiedVisitor 46implements ClassVisitor, 47 MemberVisitor, 48 ConstantVisitor, 49 AttributeVisitor, 50 BootstrapMethodInfoVisitor, 51 InnerClassesInfoVisitor, 52 ExceptionInfoVisitor, 53 StackMapFrameVisitor, 54 VerificationTypeVisitor, 55 LocalVariableInfoVisitor, 56 LocalVariableTypeInfoVisitor, 57 AnnotationVisitor, 58 ElementValueVisitor, 59 InstructionVisitor 60{ 61 // A visitor info flag to indicate the constant is being used. 62 private static final Object USED = new Object(); 63 64 private int[] constantIndexMap = new int[ClassConstants.TYPICAL_CONSTANT_POOL_SIZE]; 65 private final ConstantPoolRemapper constantPoolRemapper = new ConstantPoolRemapper(); 66 67 68 // Implementations for ClassVisitor. 69 70 public void visitProgramClass(ProgramClass programClass) 71 { 72 // Mark this class's name. 73 markConstant(programClass, programClass.u2thisClass); 74 75 // Mark the superclass class constant. 76 programClass.superClassConstantAccept(this); 77 78 // Mark the interface class constants. 79 programClass.interfaceConstantsAccept(this); 80 81 // Mark the constants referenced by the class members. 82 programClass.fieldsAccept(this); 83 programClass.methodsAccept(this); 84 85 // Mark the attributes. 86 programClass.attributesAccept(this); 87 88 // Shift the used constant pool entries together, filling out the 89 // index map. 90 int newConstantPoolCount = 91 shrinkConstantPool(programClass.constantPool, 92 programClass.u2constantPoolCount); 93 94 // Remap the references to the constant pool if it has shrunk. 95 if (newConstantPoolCount < programClass.u2constantPoolCount) 96 { 97 programClass.u2constantPoolCount = newConstantPoolCount; 98 99 // Remap all constant pool references. 100 constantPoolRemapper.setConstantIndexMap(constantIndexMap); 101 constantPoolRemapper.visitProgramClass(programClass); 102 } 103 } 104 105 106 // Implementations for MemberVisitor. 107 108 public void visitProgramMember(ProgramClass programClass, ProgramMember programMember) 109 { 110 // Mark the name and descriptor. 111 markConstant(programClass, programMember.u2nameIndex); 112 markConstant(programClass, programMember.u2descriptorIndex); 113 114 // Mark the attributes. 115 programMember.attributesAccept(programClass, this); 116 } 117 118 119 // Implementations for ConstantVisitor. 120 121 public void visitAnyConstant(Clazz clazz, Constant constant) 122 { 123 markAsUsed(constant); 124 } 125 126 127 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 128 { 129 markAsUsed(stringConstant); 130 131 markConstant(clazz, stringConstant.u2stringIndex); 132 } 133 134 135 public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) 136 { 137 markAsUsed(invokeDynamicConstant); 138 139 markConstant(clazz, invokeDynamicConstant.u2nameAndTypeIndex); 140 141 // Mark the bootstrap methods attribute. 142 clazz.attributesAccept(this); 143 } 144 145 146 public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) 147 { 148 markAsUsed(methodHandleConstant); 149 150 markConstant(clazz, methodHandleConstant.u2referenceIndex); 151 } 152 153 154 public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) 155 { 156 markAsUsed(refConstant); 157 158 markConstant(clazz, refConstant.u2classIndex); 159 markConstant(clazz, refConstant.u2nameAndTypeIndex); 160 } 161 162 163 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 164 { 165 markAsUsed(classConstant); 166 167 markConstant(clazz, classConstant.u2nameIndex); 168 } 169 170 171 public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) 172 { 173 markAsUsed(methodTypeConstant); 174 175 markConstant(clazz, methodTypeConstant.u2descriptorIndex); 176 } 177 178 179 public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) 180 { 181 markAsUsed(nameAndTypeConstant); 182 183 markConstant(clazz, nameAndTypeConstant.u2nameIndex); 184 markConstant(clazz, nameAndTypeConstant.u2descriptorIndex); 185 } 186 187 188 // Implementations for AttributeVisitor. 189 190 public void visitAnyAttribute(Clazz clazz, Attribute attribute) 191 { 192 markConstant(clazz, attribute.u2attributeNameIndex); 193 } 194 195 196 public void visitBootstrapMethodsAttribute(Clazz clazz, BootstrapMethodsAttribute bootstrapMethodsAttribute) 197 { 198 markConstant(clazz, bootstrapMethodsAttribute.u2attributeNameIndex); 199 200 // Mark the bootstrap method entries. 201 bootstrapMethodsAttribute.bootstrapMethodEntriesAccept(clazz, this); 202 } 203 204 205 public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) 206 { 207 markConstant(clazz, sourceFileAttribute.u2attributeNameIndex); 208 markConstant(clazz, sourceFileAttribute.u2sourceFileIndex); 209 } 210 211 212 public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) 213 { 214 markConstant(clazz, sourceDirAttribute.u2attributeNameIndex); 215 markConstant(clazz, sourceDirAttribute.u2sourceDirIndex); 216 } 217 218 219 public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) 220 { 221 markConstant(clazz, innerClassesAttribute.u2attributeNameIndex); 222 223 // Mark the outer class entries. 224 innerClassesAttribute.innerClassEntriesAccept(clazz, this); 225 } 226 227 228 public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) 229 { 230 markConstant(clazz, enclosingMethodAttribute.u2attributeNameIndex); 231 markConstant(clazz, enclosingMethodAttribute.u2classIndex); 232 233 if (enclosingMethodAttribute.u2nameAndTypeIndex != 0) 234 { 235 markConstant(clazz, enclosingMethodAttribute.u2nameAndTypeIndex); 236 } 237 } 238 239 240 public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) 241 { 242 markConstant(clazz, signatureAttribute.u2attributeNameIndex); 243 markConstant(clazz, signatureAttribute.u2signatureIndex); 244 } 245 246 247 public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) 248 { 249 markConstant(clazz, constantValueAttribute.u2attributeNameIndex); 250 markConstant(clazz, constantValueAttribute.u2constantValueIndex); 251 } 252 253 254 public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) 255 { 256 markConstant(clazz, exceptionsAttribute.u2attributeNameIndex); 257 258 // Mark the constant pool entries referenced by the exceptions. 259 exceptionsAttribute.exceptionEntriesAccept((ProgramClass)clazz, this); 260 } 261 262 263 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 264 { 265 markConstant(clazz, codeAttribute.u2attributeNameIndex); 266 267 // Mark the constant pool entries referenced by the instructions, 268 // by the exceptions, and by the attributes. 269 codeAttribute.instructionsAccept(clazz, method, this); 270 codeAttribute.exceptionsAccept(clazz, method, this); 271 codeAttribute.attributesAccept(clazz, method, this); 272 } 273 274 275 public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) 276 { 277 markConstant(clazz, stackMapAttribute.u2attributeNameIndex); 278 279 // Mark the constant pool entries referenced by the stack map frames. 280 stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); 281 } 282 283 284 public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) 285 { 286 markConstant(clazz, stackMapTableAttribute.u2attributeNameIndex); 287 288 // Mark the constant pool entries referenced by the stack map frames. 289 stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); 290 } 291 292 293 public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) 294 { 295 markConstant(clazz, localVariableTableAttribute.u2attributeNameIndex); 296 297 // Mark the constant pool entries referenced by the local variables. 298 localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 299 } 300 301 302 public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) 303 { 304 markConstant(clazz, localVariableTypeTableAttribute.u2attributeNameIndex); 305 306 // Mark the constant pool entries referenced by the local variable types. 307 localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 308 } 309 310 311 public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) 312 { 313 markConstant(clazz, annotationsAttribute.u2attributeNameIndex); 314 315 // Mark the constant pool entries referenced by the annotations. 316 annotationsAttribute.annotationsAccept(clazz, this); 317 } 318 319 320 public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) 321 { 322 markConstant(clazz, parameterAnnotationsAttribute.u2attributeNameIndex); 323 324 // Mark the constant pool entries referenced by the annotations. 325 parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); 326 } 327 328 329 public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) 330 { 331 markConstant(clazz, annotationDefaultAttribute.u2attributeNameIndex); 332 333 // Mark the constant pool entries referenced by the element value. 334 annotationDefaultAttribute.defaultValueAccept(clazz, this); 335 } 336 337 338 // Implementations for BootstrapMethodInfoVisitor. 339 340 public void visitBootstrapMethodInfo(Clazz clazz, BootstrapMethodInfo bootstrapMethodInfo) 341 { 342 markConstant(clazz, bootstrapMethodInfo.u2methodHandleIndex); 343 344 // Mark the constant pool entries referenced by the arguments. 345 bootstrapMethodInfo.methodArgumentsAccept(clazz, this); 346 } 347 348 349 // Implementations for InnerClassesInfoVisitor. 350 351 public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) 352 { 353 innerClassesInfo.innerClassConstantAccept(clazz, this); 354 innerClassesInfo.outerClassConstantAccept(clazz, this); 355 innerClassesInfo.innerNameConstantAccept(clazz, this); 356 } 357 358 359 // Implementations for ExceptionInfoVisitor. 360 361 public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) 362 { 363 if (exceptionInfo.u2catchType != 0) 364 { 365 markConstant(clazz, exceptionInfo.u2catchType); 366 } 367 } 368 369 370 // Implementations for StackMapFrameVisitor. 371 372 public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {} 373 374 375 public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) 376 { 377 // Mark the constant pool entries referenced by the verification types. 378 sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); 379 } 380 381 382 public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) 383 { 384 // Mark the constant pool entries referenced by the verification types. 385 moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); 386 } 387 388 389 public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) 390 { 391 // Mark the constant pool entries referenced by the verification types. 392 fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); 393 fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); 394 } 395 396 397 // Implementations for VerificationTypeVisitor. 398 399 public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} 400 401 402 public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) 403 { 404 markConstant(clazz, objectType.u2classIndex); 405 } 406 407 408 // Implementations for LocalVariableInfoVisitor. 409 410 public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) 411 { 412 markConstant(clazz, localVariableInfo.u2nameIndex); 413 markConstant(clazz, localVariableInfo.u2descriptorIndex); 414 } 415 416 417 // Implementations for LocalVariableTypeInfoVisitor. 418 419 public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) 420 { 421 markConstant(clazz, localVariableTypeInfo.u2nameIndex); 422 markConstant(clazz, localVariableTypeInfo.u2signatureIndex); 423 } 424 425 426 // Implementations for AnnotationVisitor. 427 428 public void visitAnnotation(Clazz clazz, Annotation annotation) 429 { 430 markConstant(clazz, annotation.u2typeIndex); 431 432 // Mark the constant pool entries referenced by the element values. 433 annotation.elementValuesAccept(clazz, this); 434 } 435 436 437 // Implementations for ElementValueVisitor. 438 439 public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) 440 { 441 if (constantElementValue.u2elementNameIndex != 0) 442 { 443 markConstant(clazz, constantElementValue.u2elementNameIndex); 444 } 445 446 markConstant(clazz, constantElementValue.u2constantValueIndex); 447 } 448 449 450 public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) 451 { 452 if (enumConstantElementValue.u2elementNameIndex != 0) 453 { 454 markConstant(clazz, enumConstantElementValue.u2elementNameIndex); 455 } 456 457 markConstant(clazz, enumConstantElementValue.u2typeNameIndex); 458 markConstant(clazz, enumConstantElementValue.u2constantNameIndex); 459 } 460 461 462 public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) 463 { 464 if (classElementValue.u2elementNameIndex != 0) 465 { 466 markConstant(clazz, classElementValue.u2elementNameIndex); 467 } 468 469 markConstant(clazz, classElementValue.u2classInfoIndex); 470 } 471 472 473 public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) 474 { 475 if (annotationElementValue.u2elementNameIndex != 0) 476 { 477 markConstant(clazz, annotationElementValue.u2elementNameIndex); 478 } 479 480 // Mark the constant pool entries referenced by the annotation. 481 annotationElementValue.annotationAccept(clazz, this); 482 } 483 484 485 public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) 486 { 487 if (arrayElementValue.u2elementNameIndex != 0) 488 { 489 markConstant(clazz, arrayElementValue.u2elementNameIndex); 490 } 491 492 // Mark the constant pool entries referenced by the element values. 493 arrayElementValue.elementValuesAccept(clazz, annotation, this); 494 } 495 496 497 // Implementations for InstructionVisitor. 498 499 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 500 501 502 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 503 { 504 markConstant(clazz, constantInstruction.constantIndex); 505 } 506 507 508 // Small utility methods. 509 510 /** 511 * Marks the given constant pool entry of the given class. This includes 512 * visiting any referenced objects. 513 */ 514 private void markConstant(Clazz clazz, int index) 515 { 516 clazz.constantPoolEntryAccept(index, this); 517 } 518 519 520 /** 521 * Marks the given visitor accepter as being used. 522 */ 523 private void markAsUsed(Constant constant) 524 { 525 constant.setVisitorInfo(USED); 526 } 527 528 529 /** 530 * Returns whether the given visitor accepter has been marked as being used. 531 */ 532 private boolean isUsed(VisitorAccepter visitorAccepter) 533 { 534 return visitorAccepter.getVisitorInfo() == USED; 535 } 536 537 538 /** 539 * Removes all constants that are not marked as being used from the given 540 * constant pool. 541 * @return the new number of entries. 542 */ 543 private int shrinkConstantPool(Constant[] constantPool, int length) 544 { 545 // Create a new index map, if necessary. 546 if (constantIndexMap.length < length) 547 { 548 constantIndexMap = new int[length]; 549 } 550 551 int counter = 1; 552 boolean isUsed = false; 553 554 // Shift the used constant pool entries together. 555 for (int index = 1; index < length; index++) 556 { 557 constantIndexMap[index] = counter; 558 559 Constant constant = constantPool[index]; 560 561 // Don't update the flag if this is the second half of a long entry. 562 if (constant != null) 563 { 564 isUsed = isUsed(constant); 565 } 566 567 if (isUsed) 568 { 569 constantPool[counter++] = constant; 570 } 571 } 572 573 // Clear the remaining constant pool elements. 574 Arrays.fill(constantPool, counter, length, null); 575 576 return counter; 577 } 578} 579