1/* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 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 37/** 38 * This ClassVisitor remaps all possible references to constant pool entries 39 * of the classes that it visits, based on a given index map. It is assumed that 40 * the constant pool entries themselves have already been remapped. 41 * 42 * @author Eric Lafortune 43 */ 44public class ConstantPoolRemapper 45extends SimplifiedVisitor 46implements ClassVisitor, 47 ConstantVisitor, 48 MemberVisitor, 49 AttributeVisitor, 50 InstructionVisitor, 51 InnerClassesInfoVisitor, 52 ExceptionInfoVisitor, 53 StackMapFrameVisitor, 54 VerificationTypeVisitor, 55 LocalVariableInfoVisitor, 56 LocalVariableTypeInfoVisitor, 57 AnnotationVisitor, 58 ElementValueVisitor 59{ 60 private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 61 62 private int[] constantIndexMap; 63 64 65 /** 66 * Sets the given mapping of old constant pool entry indexes to their new 67 * indexes. 68 */ 69 public void setConstantIndexMap(int[] constantIndexMap) 70 { 71 this.constantIndexMap = constantIndexMap; 72 } 73 74 75 // Implementations for ClassVisitor. 76 77 public void visitProgramClass(ProgramClass programClass) 78 { 79 // Remap the local constant pool references. 80 programClass.u2thisClass = remapConstantIndex(programClass.u2thisClass); 81 programClass.u2superClass = remapConstantIndex(programClass.u2superClass); 82 83 remapConstantIndexArray(programClass.u2interfaces, 84 programClass.u2interfacesCount); 85 86 // Remap the references of the contant pool entries themselves. 87 programClass.constantPoolEntriesAccept(this); 88 89 // Remap the references in all fields, methods, and attributes. 90 programClass.fieldsAccept(this); 91 programClass.methodsAccept(this); 92 programClass.attributesAccept(this); 93 } 94 95 96 public void visitLibraryClass(LibraryClass libraryClass) 97 { 98 } 99 100 101 // Implementations for ConstantVisitor. 102 103 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 104 { 105 classConstant.u2nameIndex = 106 remapConstantIndex(classConstant.u2nameIndex); 107 } 108 109 110 public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) 111 { 112 // Nothing to do. 113 } 114 115 116 public void visitFieldrefConstant(Clazz clazz, FieldrefConstant fieldrefConstant) 117 { 118 fieldrefConstant.u2classIndex = 119 remapConstantIndex(fieldrefConstant.u2classIndex); 120 fieldrefConstant.u2nameAndTypeIndex = 121 remapConstantIndex(fieldrefConstant.u2nameAndTypeIndex); 122 } 123 124 125 public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) 126 { 127 // Nothing to do. 128 } 129 130 131 public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) 132 { 133 // Nothing to do. 134 } 135 136 137 public void visitInterfaceMethodrefConstant(Clazz clazz, InterfaceMethodrefConstant interfaceMethodrefConstant) 138 { 139 interfaceMethodrefConstant.u2classIndex = 140 remapConstantIndex(interfaceMethodrefConstant.u2classIndex); 141 interfaceMethodrefConstant.u2nameAndTypeIndex = 142 remapConstantIndex(interfaceMethodrefConstant.u2nameAndTypeIndex); 143 } 144 145 146 public void visitLongConstant(Clazz clazz, LongConstant longConstant) 147 { 148 // Nothing to do. 149 } 150 151 152 public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) 153 { 154 methodrefConstant.u2classIndex = 155 remapConstantIndex(methodrefConstant.u2classIndex); 156 methodrefConstant.u2nameAndTypeIndex = 157 remapConstantIndex(methodrefConstant.u2nameAndTypeIndex); 158 } 159 160 161 public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) 162 { 163 nameAndTypeConstant.u2nameIndex = 164 remapConstantIndex(nameAndTypeConstant.u2nameIndex); 165 nameAndTypeConstant.u2descriptorIndex = 166 remapConstantIndex(nameAndTypeConstant.u2descriptorIndex); 167 } 168 169 170 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 171 { 172 stringConstant.u2stringIndex = 173 remapConstantIndex(stringConstant.u2stringIndex); 174 } 175 176 177 public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) 178 { 179 // Nothing to do. 180 } 181 182 183 // Implementations for MemberVisitor. 184 185 public void visitProgramField(ProgramClass programClass, ProgramField programField) 186 { 187 visitMember(programClass, programField); 188 } 189 190 191 public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) 192 { 193 visitMember(programClass, programMethod); 194 } 195 196 197 private void visitMember(ProgramClass programClass, ProgramMember programMember) 198 { 199 // Remap the local constant pool references. 200 programMember.u2nameIndex = 201 remapConstantIndex(programMember.u2nameIndex); 202 programMember.u2descriptorIndex = 203 remapConstantIndex(programMember.u2descriptorIndex); 204 205 // Remap the constant pool references of the remaining attributes. 206 programMember.attributesAccept(programClass, this); 207 } 208 209 210 public void visitLibraryField(LibraryClass libraryClass, LibraryField libraryField) 211 { 212 // Library classes are left unchanged. 213 } 214 215 216 public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) 217 { 218 // Library classes are left unchanged. 219 } 220 221 222 // Implementations for AttributeVisitor. 223 224 public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute) 225 { 226 unknownAttribute.u2attributeNameIndex = 227 remapConstantIndex(unknownAttribute.u2attributeNameIndex); 228 229 // There's not much else we can do with unknown attributes. 230 } 231 232 233 public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute) 234 { 235 sourceFileAttribute.u2attributeNameIndex = 236 remapConstantIndex(sourceFileAttribute.u2attributeNameIndex); 237 sourceFileAttribute.u2sourceFileIndex = 238 remapConstantIndex(sourceFileAttribute.u2sourceFileIndex); 239 } 240 241 242 public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute) 243 { 244 sourceDirAttribute.u2attributeNameIndex = 245 remapConstantIndex(sourceDirAttribute.u2attributeNameIndex); 246 sourceDirAttribute.u2sourceDirIndex = 247 remapConstantIndex(sourceDirAttribute.u2sourceDirIndex); 248 } 249 250 251 public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute) 252 { 253 innerClassesAttribute.u2attributeNameIndex = 254 remapConstantIndex(innerClassesAttribute.u2attributeNameIndex); 255 256 // Remap the constant pool references of the inner classes. 257 innerClassesAttribute.innerClassEntriesAccept(clazz, this); 258 } 259 260 261 public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute) 262 { 263 enclosingMethodAttribute.u2attributeNameIndex = 264 remapConstantIndex(enclosingMethodAttribute.u2attributeNameIndex); 265 enclosingMethodAttribute.u2classIndex = 266 remapConstantIndex(enclosingMethodAttribute.u2classIndex); 267 enclosingMethodAttribute.u2nameAndTypeIndex = 268 remapConstantIndex(enclosingMethodAttribute.u2nameAndTypeIndex); 269 } 270 271 272 public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute) 273 { 274 deprecatedAttribute.u2attributeNameIndex = 275 remapConstantIndex(deprecatedAttribute.u2attributeNameIndex); 276 } 277 278 279 public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute) 280 { 281 syntheticAttribute.u2attributeNameIndex = 282 remapConstantIndex(syntheticAttribute.u2attributeNameIndex); 283 } 284 285 286 public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute) 287 { 288 signatureAttribute.u2attributeNameIndex = 289 remapConstantIndex(signatureAttribute.u2attributeNameIndex); 290 signatureAttribute.u2signatureIndex = 291 remapConstantIndex(signatureAttribute.u2signatureIndex); 292 } 293 294 295 public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute) 296 { 297 constantValueAttribute.u2attributeNameIndex = 298 remapConstantIndex(constantValueAttribute.u2attributeNameIndex); 299 constantValueAttribute.u2constantValueIndex = 300 remapConstantIndex(constantValueAttribute.u2constantValueIndex); 301 } 302 303 304 public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute) 305 { 306 exceptionsAttribute.u2attributeNameIndex = 307 remapConstantIndex(exceptionsAttribute.u2attributeNameIndex); 308 309 // Remap the constant pool references of the exceptions. 310 remapConstantIndexArray(exceptionsAttribute.u2exceptionIndexTable, 311 exceptionsAttribute.u2exceptionIndexTableLength); 312 } 313 314 315 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 316 { 317 codeAttribute.u2attributeNameIndex = 318 remapConstantIndex(codeAttribute.u2attributeNameIndex); 319 320 // Initially, the code attribute editor doesn't contain any changes. 321 codeAttributeEditor.reset(codeAttribute.u4codeLength); 322 323 // Remap the constant pool references of the instructions. 324 codeAttribute.instructionsAccept(clazz, method, this); 325 326 // Apply the code atribute editor. It will only contain any changes if 327 // the code length is changing at any point. 328 codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); 329 330 // Remap the constant pool references of the exceptions and attributes. 331 codeAttribute.exceptionsAccept(clazz, method, this); 332 codeAttribute.attributesAccept(clazz, method, this); 333 } 334 335 336 public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute) 337 { 338 stackMapAttribute.u2attributeNameIndex = 339 remapConstantIndex(stackMapAttribute.u2attributeNameIndex); 340 341 // Remap the constant pool references of the stack map frames. 342 stackMapAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); 343 } 344 345 346 public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute) 347 { 348 stackMapTableAttribute.u2attributeNameIndex = 349 remapConstantIndex(stackMapTableAttribute.u2attributeNameIndex); 350 351 // Remap the constant pool references of the stack map frames. 352 stackMapTableAttribute.stackMapFramesAccept(clazz, method, codeAttribute, this); 353 } 354 355 356 public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute) 357 { 358 lineNumberTableAttribute.u2attributeNameIndex = 359 remapConstantIndex(lineNumberTableAttribute.u2attributeNameIndex); 360 } 361 362 363 public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute) 364 { 365 localVariableTableAttribute.u2attributeNameIndex = 366 remapConstantIndex(localVariableTableAttribute.u2attributeNameIndex); 367 368 // Remap the constant pool references of the local variables. 369 localVariableTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 370 } 371 372 373 public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute) 374 { 375 localVariableTypeTableAttribute.u2attributeNameIndex = 376 remapConstantIndex(localVariableTypeTableAttribute.u2attributeNameIndex); 377 378 // Remap the constant pool references of the local variables. 379 localVariableTypeTableAttribute.localVariablesAccept(clazz, method, codeAttribute, this); 380 } 381 382 383 public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute) 384 { 385 annotationsAttribute.u2attributeNameIndex = 386 remapConstantIndex(annotationsAttribute.u2attributeNameIndex); 387 388 // Remap the constant pool references of the annotations. 389 annotationsAttribute.annotationsAccept(clazz, this); 390 } 391 392 393 public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute) 394 { 395 parameterAnnotationsAttribute.u2attributeNameIndex = 396 remapConstantIndex(parameterAnnotationsAttribute.u2attributeNameIndex); 397 398 // Remap the constant pool references of the annotations. 399 parameterAnnotationsAttribute.annotationsAccept(clazz, method, this); 400 } 401 402 403 public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute) 404 { 405 annotationDefaultAttribute.u2attributeNameIndex = 406 remapConstantIndex(annotationDefaultAttribute.u2attributeNameIndex); 407 408 // Remap the constant pool references of the annotations. 409 annotationDefaultAttribute.defaultValueAccept(clazz, this); 410 } 411 412 413 // Implementations for InnerClassesInfoVisitor. 414 415 public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo) 416 { 417 if (innerClassesInfo.u2innerClassIndex != 0) 418 { 419 innerClassesInfo.u2innerClassIndex = 420 remapConstantIndex(innerClassesInfo.u2innerClassIndex); 421 } 422 423 if (innerClassesInfo.u2outerClassIndex != 0) 424 { 425 innerClassesInfo.u2outerClassIndex = 426 remapConstantIndex(innerClassesInfo.u2outerClassIndex); 427 } 428 429 if (innerClassesInfo.u2innerNameIndex != 0) 430 { 431 innerClassesInfo.u2innerNameIndex = 432 remapConstantIndex(innerClassesInfo.u2innerNameIndex); 433 } 434 } 435 436 437 // Implementations for ExceptionInfoVisitor. 438 439 public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) 440 { 441 if (exceptionInfo.u2catchType != 0) 442 { 443 exceptionInfo.u2catchType = 444 remapConstantIndex(exceptionInfo.u2catchType); 445 } 446 } 447 448 449 // Implementations for InstructionVisitor. 450 451 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 452 453 454 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 455 { 456 // Is the new constant pool index different from the original one? 457 int newConstantIndex = remapConstantIndex(constantInstruction.constantIndex); 458 if (newConstantIndex != constantInstruction.constantIndex) 459 { 460 // Replace the instruction. 461 Instruction replacementInstruction = 462 new ConstantInstruction(constantInstruction.opcode, 463 newConstantIndex, 464 constantInstruction.constant).shrink(); 465 466 codeAttributeEditor.replaceInstruction(offset, replacementInstruction); 467 } 468 } 469 470 471 // Implementations for StackMapFrameVisitor. 472 473 public void visitAnyStackMapFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, StackMapFrame stackMapFrame) {} 474 475 476 public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame) 477 { 478 // Remap the constant pool references of the verification types. 479 sameOneFrame.stackItemAccept(clazz, method, codeAttribute, offset, this); 480 } 481 482 483 public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame) 484 { 485 // Remap the constant pool references of the verification types. 486 moreZeroFrame.additionalVariablesAccept(clazz, method, codeAttribute, offset, this); 487 } 488 489 490 public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame) 491 { 492 // Remap the constant pool references of the verification types. 493 fullFrame.variablesAccept(clazz, method, codeAttribute, offset, this); 494 fullFrame.stackAccept(clazz, method, codeAttribute, offset, this); 495 } 496 497 498 // Implementations for VerificationTypeVisitor. 499 500 public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType) {} 501 502 503 public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType) 504 { 505 objectType.u2classIndex = 506 remapConstantIndex(objectType.u2classIndex); 507 } 508 509 510 // Implementations for LocalVariableInfoVisitor. 511 512 public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo) 513 { 514 localVariableInfo.u2nameIndex = 515 remapConstantIndex(localVariableInfo.u2nameIndex); 516 localVariableInfo.u2descriptorIndex = 517 remapConstantIndex(localVariableInfo.u2descriptorIndex); 518 } 519 520 521 // Implementations for LocalVariableTypeInfoVisitor. 522 523 public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo) 524 { 525 localVariableTypeInfo.u2nameIndex = 526 remapConstantIndex(localVariableTypeInfo.u2nameIndex); 527 localVariableTypeInfo.u2signatureIndex = 528 remapConstantIndex(localVariableTypeInfo.u2signatureIndex); 529 } 530 531 532 // Implementations for AnnotationVisitor. 533 534 public void visitAnnotation(Clazz clazz, Annotation annotation) 535 { 536 annotation.u2typeIndex = 537 remapConstantIndex(annotation.u2typeIndex); 538 539 // Remap the constant pool references of the element values. 540 annotation.elementValuesAccept(clazz, this); 541 } 542 543 544 // Implementations for ElementValueVisitor. 545 546 public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue) 547 { 548 constantElementValue.u2elementNameIndex = 549 remapConstantIndex(constantElementValue.u2elementNameIndex); 550 constantElementValue.u2constantValueIndex = 551 remapConstantIndex(constantElementValue.u2constantValueIndex); 552 } 553 554 555 public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue) 556 { 557 enumConstantElementValue.u2elementNameIndex = 558 remapConstantIndex(enumConstantElementValue.u2elementNameIndex); 559 enumConstantElementValue.u2typeNameIndex = 560 remapConstantIndex(enumConstantElementValue.u2typeNameIndex); 561 enumConstantElementValue.u2constantNameIndex = 562 remapConstantIndex(enumConstantElementValue.u2constantNameIndex); 563 } 564 565 566 public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue) 567 { 568 classElementValue.u2elementNameIndex = 569 remapConstantIndex(classElementValue.u2elementNameIndex); 570 classElementValue.u2classInfoIndex = 571 remapConstantIndex(classElementValue.u2classInfoIndex); 572 } 573 574 575 public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue) 576 { 577 annotationElementValue.u2elementNameIndex = 578 remapConstantIndex(annotationElementValue.u2elementNameIndex); 579 580 // Remap the constant pool references of the annotation. 581 annotationElementValue.annotationAccept(clazz, this); 582 } 583 584 585 public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue) 586 { 587 arrayElementValue.u2elementNameIndex = 588 remapConstantIndex(arrayElementValue.u2elementNameIndex); 589 590 // Remap the constant pool references of the element values. 591 arrayElementValue.elementValuesAccept(clazz, annotation, this); 592 } 593 594 595 // Small utility methods. 596 597 /** 598 * Remaps all constant pool indices in the given array. 599 */ 600 private void remapConstantIndexArray(int[] array, int length) 601 { 602 for (int index = 0; index < length; index++) 603 { 604 array[index] = remapConstantIndex(array[index]); 605 } 606 } 607 608 609 /** 610 * Returns the new constant pool index of the entry at the 611 * given index. 612 */ 613 private int remapConstantIndex(int constantIndex) 614 { 615 return constantIndexMap[constantIndex]; 616 } 617} 618