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