1 21 package proguard.preverify; 22 23 import proguard.classfile.util.*; 24 import proguard.classfile.attribute.visitor.*; 25 import proguard.classfile.attribute.*; 26 import proguard.classfile.instruction.visitor.InstructionVisitor; 27 import proguard.classfile.instruction.*; 28 import proguard.classfile.editor.*; 29 import proguard.classfile.*; 30 import proguard.classfile.visitor.*; 31 import proguard.optimize.peephole.BranchTargetFinder; 32 33 39 public class CodeSubroutineInliner 40 extends SimplifiedVisitor 41 implements AttributeVisitor, 42 InstructionVisitor, 43 ExceptionInfoVisitor 44 { 45 private static final boolean DEBUG = false; 47 50 51 52 private BranchTargetFinder branchTargetFinder = new BranchTargetFinder(); 53 private CodeAttributeComposer codeAttributeComposer = new CodeAttributeComposer(); 54 55 private boolean inlinedAny; 56 private ExceptionInfoVisitor subroutineExceptionInliner; 57 58 59 61 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 62 63 64 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 65 { 66 70 branchTargetFinder.visitCodeAttribute(clazz, method, codeAttribute); 71 72 if (!containsSubroutines(codeAttribute)) 74 { 75 return; 76 } 77 78 inlinedAny = false; 79 subroutineExceptionInliner = this; 80 codeAttributeComposer.reset(); 81 82 copyCode(clazz, method, codeAttribute); 84 85 if (inlinedAny) 87 { 88 codeAttributeComposer.visitCodeAttribute(clazz, method, codeAttribute); 89 } 90 } 91 92 93 96 private boolean containsSubroutines(CodeAttribute codeAttribute) 97 { 98 for (int offset = 0; offset < codeAttribute.u4codeLength; offset++) 99 { 100 if (branchTargetFinder.isSubroutineInvocation(offset)) 101 { 102 return true; 103 } 104 } 105 106 return false; 107 } 108 109 110 113 private void copyCode(Clazz clazz, 114 Method method, 115 CodeAttribute codeAttribute) 116 { 117 if (DEBUG) 118 { 119 System.out.println("SubroutineInliner: processing ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 120 } 121 122 codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); 123 124 int offset = 0; 126 while (offset < codeAttribute.u4codeLength) 127 { 128 Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); 129 int instructionLength = instruction.length(offset); 130 131 if (branchTargetFinder.isSubroutine(offset) && 133 branchTargetFinder.isSubroutineReturning(offset)) 134 { 135 if (DEBUG && branchTargetFinder.isSubroutineStart(offset)) 137 { 138 System.out.println("Skipping subroutine at ["+offset+"]"); 139 } 140 141 codeAttributeComposer.appendLabel(offset); 143 } 144 else 145 { 146 instruction.accept(clazz, method, codeAttribute, offset, this); 148 } 149 150 offset += instructionLength; 151 } 152 153 codeAttribute.exceptionsAccept(clazz, method, this); 156 157 if (DEBUG) 158 { 159 System.out.println("Appending label after code at ["+offset+"]"); 160 } 161 162 codeAttributeComposer.appendLabel(codeAttribute.u4codeLength); 164 165 codeAttributeComposer.endCodeFragment(); 166 } 167 168 169 172 private void inlineSubroutine(Clazz clazz, 173 Method method, 174 CodeAttribute codeAttribute, 175 int subroutineInvocationOffset, 176 int subroutineStart) 177 { 178 int subroutineEnd = branchTargetFinder.subroutineEnd(subroutineStart); 179 180 if (DEBUG) 181 { 182 System.out.println("Inlining subroutine ["+subroutineStart+" -> "+subroutineEnd+"] at ["+subroutineInvocationOffset+"]"); 183 } 184 185 ExceptionInfoVisitor oldSubroutineExceptionInliner = 188 subroutineExceptionInliner; 189 190 subroutineExceptionInliner = 191 new ExceptionExcludedOffsetFilter(subroutineInvocationOffset, 192 subroutineExceptionInliner); 193 194 codeAttributeComposer.beginCodeFragment(codeAttribute.u4codeLength); 195 196 codeAttribute.instructionsAccept(clazz, 199 method, 200 subroutineStart, 201 subroutineEnd, 202 this); 203 204 if (DEBUG) 205 { 206 System.out.println("Appending label after inlined subroutine at ["+subroutineEnd+"]"); 207 } 208 209 codeAttributeComposer.appendLabel(subroutineEnd); 211 212 subroutineExceptionInliner = oldSubroutineExceptionInliner; 215 216 codeAttribute.exceptionsAccept(clazz, 218 method, 219 subroutineStart, 220 subroutineEnd, 221 subroutineExceptionInliner); 222 223 codeAttributeComposer.endCodeFragment(); 224 225 inlinedAny = true; 226 } 227 228 229 231 public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) 232 { 233 codeAttributeComposer.appendInstruction(offset, instruction.shrink()); 235 } 236 237 238 public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 239 { 240 byte opcode = variableInstruction.opcode; 241 if (opcode == InstructionConstants.OP_RET) 242 { 243 if (branchTargetFinder.subroutineEnd(offset) == offset + variableInstruction.length(offset)) 245 { 246 if (DEBUG) 247 { 248 System.out.println("Replacing subroutine return at ["+offset+"] by a label"); 249 } 250 251 codeAttributeComposer.appendLabel(offset); 253 } 254 else 255 { 256 if (DEBUG) 257 { 258 System.out.println("Replacing subroutine return at ["+offset+"] by a simple branch"); 259 } 260 261 Instruction replacementInstruction = 263 new BranchInstruction(InstructionConstants.OP_GOTO, 264 branchTargetFinder.subroutineEnd(offset) - offset).shrink(); 265 266 codeAttributeComposer.appendInstruction(offset, replacementInstruction); 267 } 268 } 269 else if (branchTargetFinder.isSubroutineStart(offset)) 270 { 271 if (DEBUG) 272 { 273 System.out.println("Replacing first subroutine instruction at ["+offset+"] by a label"); 274 } 275 276 codeAttributeComposer.appendLabel(offset); 279 } 280 else 281 { 282 codeAttributeComposer.appendInstruction(offset, variableInstruction); 284 } 285 } 286 287 288 public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 289 { 290 byte opcode = branchInstruction.opcode; 291 if (opcode == InstructionConstants.OP_JSR || 292 opcode == InstructionConstants.OP_JSR_W) 293 { 294 int branchOffset = branchInstruction.branchOffset; 295 int branchTarget = offset + branchOffset; 296 297 if (branchTargetFinder.isSubroutineReturning(branchTarget)) 299 { 300 codeAttributeComposer.appendLabel(offset); 302 303 inlineSubroutine(clazz, 305 method, 306 codeAttribute, 307 offset, 308 branchTarget); 309 } 310 else 311 { 312 if (DEBUG) 313 { 314 System.out.println("Replacing subroutine invocation at ["+offset+"] by a simple branch"); 315 } 316 317 Instruction replacementInstruction = 319 new BranchInstruction(InstructionConstants.OP_GOTO, 320 branchOffset).shrink(); 321 322 codeAttributeComposer.appendInstruction(offset, replacementInstruction); 323 324 inlinedAny = true; 325 } 326 } 327 else 328 { 329 codeAttributeComposer.appendInstruction(offset, branchInstruction); 331 } 332 } 333 334 335 337 public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) 338 { 339 int startPC = exceptionInfo.u2startPC; 340 int endPC = exceptionInfo.u2endPC; 341 int handlerPC = exceptionInfo.u2handlerPC; 342 int catchType = exceptionInfo.u2catchType; 343 344 int offset = startPC; 347 while (offset < endPC) 348 { 349 Instruction instruction = InstructionFactory.create(codeAttribute.code, offset); 350 int instructionLength = instruction.length(offset); 351 352 if (branchTargetFinder.isSubroutineInvocation(offset) && 354 !exceptionInfo.isApplicable(offset + ((BranchInstruction)instruction).branchOffset)) 355 { 356 codeAttributeComposer.appendException(new ExceptionInfo(startPC, 358 offset, 359 handlerPC, 360 catchType)); 361 362 startPC = offset + instructionLength; 364 } 365 366 offset += instructionLength; 367 } 368 369 codeAttributeComposer.appendException(new ExceptionInfo(startPC, 372 endPC, 373 handlerPC, 374 catchType)); 375 376 } 378 } 379 | Popular Tags |