1 21 package proguard.classfile.editor; 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.instruction.*; 29 import proguard.classfile.instruction.visitor.InstructionVisitor; 30 import proguard.classfile.util.*; 31 import proguard.classfile.visitor.*; 32 33 39 public class MethodInvocationFixer 40 extends SimplifiedVisitor 41 implements AttributeVisitor, 42 InstructionVisitor, 43 ConstantVisitor, 44 ClassVisitor, 45 MemberVisitor 46 { 47 private static final boolean DEBUG = false; 48 49 50 private CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 51 52 private Clazz referencedClass; 54 private Clazz referencedMethodClass; 55 private Member referencedMethod; 56 57 58 60 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 61 62 63 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 64 { 65 codeAttributeEditor.reset(codeAttribute.u4codeLength); 67 68 codeAttribute.instructionsAccept(clazz, method, this); 70 71 codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); 73 } 74 75 76 78 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 79 80 81 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 82 { 83 int constantIndex = constantInstruction.constantIndex; 84 85 referencedMethod = null; 87 88 clazz.constantPoolEntryAccept(constantIndex, this); 89 90 if (referencedMethod != null) 92 { 93 byte opcode = constantInstruction.opcode; 95 96 if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_STATIC) != 0) 98 { 99 if (opcode != InstructionConstants.OP_INVOKESTATIC) 101 { 102 Instruction replacementInstruction = 104 new ConstantInstruction(InstructionConstants.OP_INVOKESTATIC, 105 constantIndex).shrink(); 106 107 codeAttributeEditor.replaceInstruction(offset, replacementInstruction); 108 109 if (DEBUG) 110 { 111 debug(clazz, method, offset, constantInstruction, replacementInstruction); 112 } 113 } 114 } 115 116 else if ((referencedMethod.getAccessFlags() & ClassConstants.INTERNAL_ACC_PRIVATE) != 0 || 118 referencedMethod.getName(referencedMethodClass).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) 119 { 120 if (opcode != InstructionConstants.OP_INVOKESPECIAL) 122 { 123 Instruction replacementInstruction = 125 new ConstantInstruction(InstructionConstants.OP_INVOKESPECIAL, 126 constantIndex).shrink(); 127 128 codeAttributeEditor.replaceInstruction(offset, replacementInstruction); 129 130 if (DEBUG) 131 { 132 debug(clazz, method, offset, constantInstruction, replacementInstruction); 133 } 134 } 135 } 136 137 else if ((referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0) 139 { 140 int invokeinterfaceConstant = 141 (ClassUtil.internalMethodParameterSize(referencedMethod.getDescriptor(referencedMethodClass)) + 1) << 8; 142 143 if (opcode != InstructionConstants.OP_INVOKEINTERFACE || 146 constantInstruction.constant != invokeinterfaceConstant) 147 { 148 Instruction replacementInstruction = 150 new ConstantInstruction(InstructionConstants.OP_INVOKEINTERFACE, 151 constantIndex, 152 invokeinterfaceConstant).shrink(); 153 154 codeAttributeEditor.replaceInstruction(offset, replacementInstruction); 155 156 if (DEBUG) 157 { 158 debug(clazz, method, offset, constantInstruction, replacementInstruction); 159 } 160 } 161 } 162 163 else 166 { 167 if (opcode != InstructionConstants.OP_INVOKEVIRTUAL && 170 (opcode != InstructionConstants.OP_INVOKESPECIAL || 171 !clazz.extends_(referencedClass))) 172 { 173 Instruction replacementInstruction = 175 new ConstantInstruction(InstructionConstants.OP_INVOKEVIRTUAL, 176 constantIndex).shrink(); 177 178 codeAttributeEditor.replaceInstruction(offset, replacementInstruction); 179 180 if (DEBUG) 181 { 182 debug(clazz, method, offset, constantInstruction, replacementInstruction); 183 } 184 } 185 } 186 } 187 } 188 189 190 192 public void visitAnyConstant(Clazz clazz, Constant constant) {} 193 194 195 public void visitAnyMethodrefConstant(Clazz clazz, RefConstant refConstant) 196 { 197 clazz.constantPoolEntryAccept(refConstant.u2classIndex, this); 202 203 refConstant.referencedMemberAccept(this); 205 } 206 207 208 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 209 { 210 classConstant.referencedClassAccept(this); 212 } 213 214 215 217 public void visitAnyClass(Clazz clazz) 218 { 219 referencedClass = clazz; 221 } 222 223 224 226 public void visitAnyMember(Clazz clazz, Member member) 227 { 228 referencedMethodClass = clazz; 230 referencedMethod = member; 231 } 232 233 234 236 private void debug(Clazz clazz, 237 Method method, 238 int offset, 239 ConstantInstruction constantInstruction, 240 Instruction replacementInstruction) 241 { 242 System.out.println("MethodInvocationFixer:"); 243 System.out.println(" Class = "+clazz.getName()); 244 System.out.println(" Method = "+method.getName(clazz)+method.getDescriptor(clazz)); 245 System.out.println(" Instruction = "+constantInstruction.toString(offset)); 246 System.out.println(" -> Class = "+referencedClass); 247 System.out.println(" Method = "+referencedMethod); 248 if ((referencedClass.getAccessFlags() & ClassConstants.INTERNAL_ACC_INTERFACE) != 0) 249 { 250 System.out.println(" Parameter size = "+(ClassUtil.internalMethodParameterSize(referencedMethod.getDescriptor(referencedMethodClass)+1))); 251 } 252 System.out.println(" Replacement instruction = "+replacementInstruction.toString(offset)); 253 } 254 } 255 | Popular Tags |