1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2009 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.optimize; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.AttributeVisitor; 26 import proguard.classfile.constant.*; 27 import proguard.classfile.constant.visitor.ConstantVisitor; 28 import proguard.classfile.editor.CodeAttributeEditor; 29 import proguard.classfile.instruction.*; 30 import proguard.classfile.instruction.visitor.InstructionVisitor; 31 import proguard.classfile.util.SimplifiedVisitor; 32 import proguard.classfile.visitor.MemberVisitor; 33 34 /** 35 * This AttributeVisitor adds an additional integer parameter to the tweaked 36 * initialization method invocations that it visits. 37 */ 38 public class DuplicateInitializerInvocationFixer 39 extends SimplifiedVisitor 40 implements AttributeVisitor, 41 InstructionVisitor, 42 ConstantVisitor, 43 MemberVisitor 44 { 45 private static final boolean DEBUG = false; 46 47 private final InstructionVisitor extraAddedInstructionVisitor; 48 49 private final CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 50 51 private String descriptor; 52 private boolean hasBeenFixed; 53 54 55 /** 56 * Creates a new EvaluationSimplifier. 57 */ 58 public DuplicateInitializerInvocationFixer() 59 { 60 this(null); 61 } 62 63 64 /** 65 * Creates a new EvaluationSimplifier. 66 * @param extraAddedInstructionVisitor an optional extra visitor for all 67 * added instructions. 68 */ 69 public DuplicateInitializerInvocationFixer(InstructionVisitor extraAddedInstructionVisitor) 70 { 71 this.extraAddedInstructionVisitor = extraAddedInstructionVisitor; 72 } 73 74 75 // Implementations for AttributeVisitor. 76 77 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 78 79 80 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 81 { 82 83 // Reset the code changes. 84 codeAttributeEditor.reset(codeAttribute.u4codeLength); 85 86 // Fix any duplicate constructor invocations. 87 codeAttribute.instructionsAccept(clazz, 88 method, 89 this); 90 91 // Apply all accumulated changes to the code. 92 codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); 93 } 94 95 96 // Implementations for InstructionVisitor. 97 98 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 99 100 101 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 102 { 103 if (constantInstruction.opcode == InstructionConstants.OP_INVOKESPECIAL) 104 { 105 hasBeenFixed = false; 106 clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); 107 108 if (hasBeenFixed) 109 { 110 Instruction extraInstruction = 111 new SimpleInstruction(InstructionConstants.OP_ICONST_0); 112 113 codeAttributeEditor.insertBeforeInstruction(offset, 114 extraInstruction); 115 116 if (DEBUG) 117 { 118 System.out.println("DuplicateInitializerInvocationFixer:"); 119 System.out.println(" Inserting "+extraInstruction.toString()+" before "+constantInstruction.toString(offset)); 120 } 121 122 if (extraAddedInstructionVisitor != null) 123 { 124 extraInstruction.accept(null, null, null, offset, extraAddedInstructionVisitor); 125 } 126 } 127 } 128 } 129 130 131 // Implementations for ConstantVisitor. 132 133 public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) 134 { 135 // Check the referenced constructor descriptor. 136 descriptor = methodrefConstant.getType(clazz); 137 methodrefConstant.referencedMemberAccept(this); 138 } 139 140 141 // Implementations for MemberVisitor. 142 143 public void visitLibraryMethod(LibraryClass libraryClass, LibraryMethod libraryMethod) {} 144 145 146 public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod) 147 { 148 hasBeenFixed = !descriptor.equals(programMethod.getDescriptor(programClass)); 149 } 150 }