1 21 package proguard.optimize.peephole; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.AttributeVisitor; 26 import proguard.classfile.editor.CodeAttributeEditor; 27 import proguard.classfile.instruction.*; 28 import proguard.classfile.instruction.visitor.InstructionVisitor; 29 import proguard.classfile.util.SimplifiedVisitor; 30 31 38 public class GotoCommonCodeReplacer 39 extends SimplifiedVisitor 40 implements AttributeVisitor, 41 InstructionVisitor 42 { 43 private static final boolean DEBUG = false; 44 45 46 private InstructionVisitor extraInstructionVisitor; 47 48 private BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); 49 private CodeAttributeEditor codeAttributeEditor = new CodeAttributeEditor(); 50 51 52 57 public GotoCommonCodeReplacer(InstructionVisitor extraInstructionVisitor) 58 { 59 this.extraInstructionVisitor = extraInstructionVisitor; 60 } 61 62 63 65 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 66 67 68 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 69 { 70 branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute); 72 73 codeAttributeEditor.reset(codeAttribute.u4codeLength); 75 76 codeAttribute.instructionsAccept(clazz, method, this); 78 79 codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute); 81 } 82 83 84 86 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {} 87 88 89 public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 90 { 91 byte opcode = branchInstruction.opcode; 94 if ((opcode == InstructionConstants.OP_GOTO || 95 opcode == InstructionConstants.OP_GOTO_W) && 96 !branchTargetFinder.isBranchTarget(offset)) 97 { 98 int branchOffset = branchInstruction.branchOffset; 99 int targetOffset = offset + branchOffset; 100 101 int commonCount = commonByteCodeCount(codeAttribute, offset, targetOffset); 103 104 if (commonCount > 0 && 105 !exceptionBoundary(codeAttribute, offset, targetOffset)) 106 { 107 if (DEBUG) 108 { 109 System.out.println("GotoCommonCodeReplacer: "+clazz.getName()+"."+method.getName(clazz)+" ("+commonCount+" instructions)"); 110 } 111 112 for (int delta = 0; delta <= commonCount; delta++) 114 { 115 int deleteOffset = offset - delta; 116 if (branchTargetFinder.isInstruction(deleteOffset)) 117 { 118 codeAttributeEditor.replaceInstruction( deleteOffset, null); 119 codeAttributeEditor.insertBeforeInstruction(deleteOffset, null); 120 codeAttributeEditor.insertAfterInstruction( deleteOffset, null); 121 122 codeAttributeEditor.deleteInstruction(deleteOffset); 123 } 124 } 125 126 int newBranchOffset = branchOffset - commonCount; 128 if (newBranchOffset != branchInstruction.length(offset)) 129 { 130 Instruction newGotoInstruction = 131 new BranchInstruction(opcode, newBranchOffset); 132 codeAttributeEditor.replaceInstruction(offset, 133 newGotoInstruction); 134 } 135 136 if (extraInstructionVisitor != null) 138 { 139 extraInstructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, branchInstruction); 140 } 141 } 142 } 143 } 144 145 146 148 152 private int commonByteCodeCount(CodeAttribute codeAttribute, int offset1, int offset2) 153 { 154 byte[] code = codeAttribute.code; 156 157 int successfulDelta = 0; 158 159 for (int delta = 1; 160 delta <= offset1 && 161 delta <= offset2 && 162 offset2 - delta != offset1; 163 delta++) 164 { 165 int newOffset1 = offset1 - delta; 166 int newOffset2 = offset2 - delta; 167 168 if (code[newOffset1] != code[newOffset2]) 170 { 171 break; 172 } 173 174 if (branchTargetFinder.isInstruction(newOffset1) ^ 176 branchTargetFinder.isInstruction(newOffset2)) 177 { 178 break; 179 } 180 181 if (branchTargetFinder.isInstruction(newOffset1) && 183 branchTargetFinder.isInstruction(newOffset2)) 184 { 185 if (branchTargetFinder.isBranchOrigin(newOffset1) || 191 branchTargetFinder.isBranchTarget(newOffset1) || 192 branchTargetFinder.isExceptionStart(newOffset1) || 193 branchTargetFinder.isExceptionEnd(newOffset1) || 194 branchTargetFinder.isInitializer(newOffset1) || 195 branchTargetFinder.isExceptionStart(newOffset2) || 196 branchTargetFinder.isExceptionEnd(newOffset2) || 197 isPop(code[newOffset1])) 198 { 199 break; 200 } 201 202 if (branchTargetFinder.isBranchTarget(newOffset2)) 205 { 206 successfulDelta = delta; 207 } 208 209 if (branchTargetFinder.isBranchTarget(newOffset1)) 210 { 211 break; 212 } 213 } 214 } 215 216 return successfulDelta; 217 } 218 219 220 224 private boolean isPop(byte opcode) 225 { 226 return opcode == InstructionConstants.OP_POP || 227 opcode == InstructionConstants.OP_POP2 || 228 opcode == InstructionConstants.OP_ARRAYLENGTH; 229 } 230 231 232 236 private boolean exceptionBoundary(CodeAttribute codeAttribute, int offset1, int offset2) 237 { 238 if (offset2 < offset1) 240 { 241 int offset = offset1; 242 offset1 = offset2; 243 offset2 = offset; 244 } 245 246 for (int offset = offset1; offset <= offset2; offset++) 248 { 249 if (branchTargetFinder.isExceptionStart(offset) || 250 branchTargetFinder.isExceptionEnd(offset)) 251 { 252 return true; 253 } 254 } 255 256 return false; 257 } 258 } 259 | Popular Tags |