1 21 package proguard.optimize.peephole; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.*; 25 import proguard.classfile.attribute.visitor.*; 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.SimplifiedVisitor; 31 32 38 public class BranchTargetFinder 39 extends SimplifiedVisitor 40 implements AttributeVisitor, 41 InstructionVisitor, 42 ExceptionInfoVisitor, 43 ConstantVisitor 44 { 45 private static final boolean DEBUG = false; 47 50 51 public static final int NONE = -2; 52 public static final int AT_METHOD_ENTRY = -1; 53 54 private static final short INSTRUCTION = 1 << 0; 55 private static final short BRANCH_ORIGIN = 1 << 1; 56 private static final short BRANCH_TARGET = 1 << 2; 57 private static final short AFTER_BRANCH = 1 << 3; 58 private static final short EXCEPTION_START = 1 << 4; 59 private static final short EXCEPTION_END = 1 << 5; 60 private static final short EXCEPTION_HANDLER = 1 << 6; 61 private static final short SUBROUTINE_INVOCATION = 1 << 7; 62 private static final short SUBROUTINE_RETURNING = 1 << 8; 63 64 private static final int MAXIMUM_CREATION_OFFSETS = 32; 65 66 67 private short[] instructionMarks = new short[ClassConstants.TYPICAL_CODE_LENGTH + 1]; 68 private int[] subroutineStarts = new int[ClassConstants.TYPICAL_CODE_LENGTH]; 69 private int[] subroutineEnds = new int[ClassConstants.TYPICAL_CODE_LENGTH]; 70 private int[] creationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; 71 private int[] initializationOffsets = new int[ClassConstants.TYPICAL_CODE_LENGTH]; 72 private int superInitializationOffset; 73 74 private int currentSubroutineStart; 75 private int currentSubroutineEnd; 76 private int[] recentCreationOffsets = new int[MAXIMUM_CREATION_OFFSETS]; 77 private int recentCreationOffsetIndex; 78 private boolean isInitializer; 79 80 81 85 public boolean isInstruction(int offset) 86 { 87 return (instructionMarks[offset] & INSTRUCTION) != 0; 88 } 89 90 91 95 public boolean isTarget(int offset) 96 { 97 return offset == 0 || 98 (instructionMarks[offset] & (BRANCH_TARGET | 99 EXCEPTION_START | 100 EXCEPTION_END | 101 EXCEPTION_HANDLER)) != 0; 102 } 103 104 105 109 public boolean isBranchOrigin(int offset) 110 { 111 return (instructionMarks[offset] & BRANCH_ORIGIN) != 0; 112 } 113 114 115 119 public boolean isBranchTarget(int offset) 120 { 121 return (instructionMarks[offset] & BRANCH_TARGET) != 0; 122 } 123 124 125 130 public boolean isAfterBranch(int offset) 131 { 132 return (instructionMarks[offset] & AFTER_BRANCH) != 0; 133 } 134 135 136 140 public boolean isExceptionStart(int offset) 141 { 142 return (instructionMarks[offset] & EXCEPTION_START) != 0; 143 } 144 145 146 150 public boolean isExceptionEnd(int offset) 151 { 152 return (instructionMarks[offset] & EXCEPTION_END) != 0; 153 } 154 155 156 160 public boolean isExceptionHandler(int offset) 161 { 162 return (instructionMarks[offset] & EXCEPTION_HANDLER) != 0; 163 } 164 165 166 170 public boolean isSubroutineInvocation(int offset) 171 { 172 return (instructionMarks[offset] & SUBROUTINE_INVOCATION) != 0; 173 } 174 175 176 180 public boolean isSubroutineStart(int offset) 181 { 182 return subroutineStarts[offset] == offset; 183 } 184 185 186 190 public boolean isSubroutine(int offset) 191 { 192 return subroutineStarts[offset] != NONE; 193 } 194 195 196 200 public boolean isSubroutineReturning(int offset) 201 { 202 return (instructionMarks[offset] & SUBROUTINE_RETURNING) != 0; 203 } 204 205 206 210 public int subroutineStart(int offset) 211 { 212 return subroutineStarts[offset]; 213 } 214 215 216 220 public int subroutineEnd(int offset) 221 { 222 return subroutineEnds[offset]; 223 } 224 225 226 230 public boolean isNew(int offset) 231 { 232 return initializationOffsets[offset] != NONE; 233 } 234 235 236 241 public int initializationOffset(int offset) 242 { 243 return initializationOffsets[offset]; 244 } 245 246 247 251 public boolean isInitializer() 252 { 253 return superInitializationOffset != NONE; 254 } 255 256 257 262 public int superInitializationOffset() 263 { 264 return superInitializationOffset; 265 } 266 267 268 273 public boolean isInitializer(int offset) 274 { 275 return creationOffsets[offset] != NONE; 276 } 277 278 279 286 public int creationOffset(int offset) 287 { 288 return creationOffsets[offset]; 289 } 290 291 292 294 public void visitAnyAttribute(Clazz clazz, Attribute attribute) {} 295 296 297 public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute) 298 { 299 303 int codeLength = codeAttribute.u4codeLength; 305 if (subroutineStarts.length < codeLength) 306 { 307 instructionMarks = new short[codeLength + 1]; 309 subroutineStarts = new int[codeLength]; 310 subroutineEnds = new int[codeLength]; 311 creationOffsets = new int[codeLength]; 312 initializationOffsets = new int[codeLength]; 313 314 for (int index = 0; index < codeLength; index++) 316 { 317 subroutineStarts[index] = NONE; 318 subroutineEnds[index] = NONE; 319 creationOffsets[index] = NONE; 320 initializationOffsets[index] = NONE; 321 } 322 } 323 else 324 { 325 for (int index = 0; index < codeLength; index++) 327 { 328 instructionMarks[index] = 0; 329 subroutineStarts[index] = NONE; 330 subroutineEnds[index] = NONE; 331 creationOffsets[index] = NONE; 332 initializationOffsets[index] = NONE; 333 } 334 335 instructionMarks[codeLength] = 0; 336 } 337 338 superInitializationOffset = NONE; 339 340 currentSubroutineStart = NONE; 342 currentSubroutineEnd = NONE; 343 344 recentCreationOffsetIndex = 0; 345 346 if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)) 349 { 350 recentCreationOffsets[recentCreationOffsetIndex++] = AT_METHOD_ENTRY; 351 } 352 353 instructionMarks[codeLength] = BRANCH_TARGET; 355 356 codeAttribute.instructionsAccept(clazz, method, this); 358 359 codeAttribute.exceptionsAccept(clazz, method, this); 361 362 365 int subroutineStart = NONE; 367 int subroutineEnd = codeLength; 368 boolean subroutineReturning = false; 369 370 for (int index = codeLength - 1; index >= 0; index--) 371 { 372 if (isInstruction(index)) 373 { 374 if (subroutineStarts[index] != NONE) 376 { 377 subroutineStart = subroutineStarts[index]; 379 } 380 else if (subroutineStart != NONE) 381 { 382 subroutineStarts[index] = subroutineStart; 384 } 385 386 if (isSubroutineStart(index)) 388 { 389 subroutineStart = NONE; 391 } 392 393 if (isSubroutine(index)) 395 { 396 subroutineEnds[index] = subroutineEnd; 398 399 if (isSubroutineReturning(index)) 401 { 402 subroutineReturning = true; 403 } 404 else if (subroutineReturning) 405 { 406 instructionMarks[index] |= SUBROUTINE_RETURNING; 407 } 408 } 409 else 410 { 411 subroutineEnd = index; 413 subroutineReturning = false; 414 } 415 } 416 } 417 418 if (DEBUG) 419 { 420 System.out.println(); 421 System.out.println("Branch targets: "+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)); 422 423 for (int index = 0; index < codeLength; index++) 424 { 425 if (isInstruction(index)) 426 { 427 System.out.println("" + 428 (isBranchOrigin(index) ? 'B' : '-') + 429 (isBranchTarget(index) ? 'T' : '-') + 430 (isExceptionStart(index) ? 'E' : '-') + 431 (isExceptionEnd(index) ? 'E' : '-') + 432 (isExceptionHandler(index) ? 'H' : '-') + 433 (isSubroutineInvocation(index) ? 'J' : '-') + 434 (isSubroutineStart(index) ? 'S' : '-') + 435 (isSubroutineReturning(index) ? 'r' : '-') + 436 (isSubroutine(index) ? " ["+subroutineStart(index)+" -> "+subroutineEnd(index)+"] " : " ") + 437 InstructionFactory.create(codeAttribute.code, index).toString(index)); 438 } 439 } 440 } 441 } 442 443 444 446 public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) 447 { 448 instructionMarks[offset] |= INSTRUCTION; 450 451 checkSubroutine(offset); 453 454 byte opcode = simpleInstruction.opcode; 455 if (opcode == InstructionConstants.OP_IRETURN || 456 opcode == InstructionConstants.OP_LRETURN || 457 opcode == InstructionConstants.OP_FRETURN || 458 opcode == InstructionConstants.OP_DRETURN || 459 opcode == InstructionConstants.OP_ARETURN || 460 opcode == InstructionConstants.OP_ATHROW) 461 { 462 markBranchOrigin(offset); 464 465 markAfterBranchOrigin(offset + simpleInstruction.length(offset)); 467 } 468 } 469 470 471 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 472 { 473 instructionMarks[offset] |= INSTRUCTION; 475 476 checkSubroutine(offset); 478 479 if (constantInstruction.opcode == InstructionConstants.OP_NEW) 481 { 482 recentCreationOffsets[recentCreationOffsetIndex++] = offset; 484 } 485 else 486 { 487 isInitializer = false; 489 clazz.constantPoolEntryAccept(constantInstruction.constantIndex, this); 490 if (isInitializer) 491 { 492 int recentCreationOffset = recentCreationOffsets[--recentCreationOffsetIndex]; 494 495 creationOffsets[offset] = recentCreationOffset; 497 498 if (recentCreationOffset == AT_METHOD_ENTRY) 500 { 501 superInitializationOffset = offset; 502 } 503 else 504 { 505 initializationOffsets[recentCreationOffset] = offset; 506 } 507 } 508 } 509 } 510 511 512 public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 513 { 514 instructionMarks[offset] |= INSTRUCTION; 516 517 checkSubroutine(offset); 519 520 if (variableInstruction.opcode == InstructionConstants.OP_RET) 521 { 522 markBranchOrigin(offset); 524 525 instructionMarks[offset] |= SUBROUTINE_RETURNING; 527 528 markAfterBranchOrigin(offset + variableInstruction.length(offset)); 530 } 531 } 532 533 534 public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 535 { 536 markBranchOrigin(offset); 538 539 checkSubroutine(offset); 541 542 markBranchTarget(offset, branchInstruction.branchOffset); 544 545 byte opcode = branchInstruction.opcode; 546 if (opcode == InstructionConstants.OP_JSR || 547 opcode == InstructionConstants.OP_JSR_W) 548 { 549 instructionMarks[offset] |= SUBROUTINE_INVOCATION; 551 552 int targetOffset = offset + branchInstruction.branchOffset; 554 subroutineStarts[targetOffset] = targetOffset; 555 } 556 else if (opcode == InstructionConstants.OP_GOTO || 557 opcode == InstructionConstants.OP_GOTO_W) 558 { 559 markAfterBranchOrigin(offset + branchInstruction.length(offset)); 561 } 562 } 563 564 565 public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction) 566 { 567 markBranchOrigin(offset); 569 570 checkSubroutine(offset); 572 573 markBranchTarget(offset, switchInstruction.defaultOffset); 575 576 markBranchTargets(offset, 578 switchInstruction.jumpOffsets); 579 580 markAfterBranchOrigin(offset + switchInstruction.length(offset)); 582 } 583 584 585 587 public void visitAnyConstant(Clazz clazz, Constant constant) {} 588 589 590 public void visitMethodrefConstant(Clazz clazz, MethodrefConstant methodrefConstant) 591 { 592 isInitializer = methodrefConstant.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT); 593 } 594 595 596 598 public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo) 599 { 600 instructionMarks[exceptionInfo.u2startPC] |= EXCEPTION_START; 602 instructionMarks[exceptionInfo.u2endPC] |= EXCEPTION_END; 603 instructionMarks[exceptionInfo.u2handlerPC] |= EXCEPTION_HANDLER; 604 } 605 606 607 609 613 private void markBranchTargets(int offset, int[] jumpOffsets) 614 { 615 for (int index = 0; index < jumpOffsets.length; index++) 616 { 617 markBranchTarget(offset, jumpOffsets[index]); 618 } 619 } 620 621 622 625 private void markBranchOrigin(int offset) 626 { 627 instructionMarks[offset] |= INSTRUCTION | BRANCH_ORIGIN; 628 } 629 630 631 634 private void markBranchTarget(int offset, int jumpOffset) 635 { 636 int targetOffset = offset + jumpOffset; 637 638 instructionMarks[targetOffset] |= BRANCH_TARGET; 639 640 if (isSubroutine(offset)) 642 { 643 subroutineStarts[targetOffset] = currentSubroutineStart; 645 646 if (currentSubroutineEnd < targetOffset) 648 { 649 currentSubroutineEnd = targetOffset; 650 } 651 } 652 } 653 654 655 658 private void markAfterBranchOrigin(int nextOffset) 659 { 660 instructionMarks[nextOffset] |= AFTER_BRANCH; 661 662 if (currentSubroutineEnd <= nextOffset) 664 { 665 currentSubroutineStart = NONE; 667 } 668 } 669 670 671 674 private void checkSubroutine(int offset) 675 { 676 if (isSubroutine(offset)) 678 { 679 currentSubroutineStart = subroutineStarts[offset]; 681 } 682 else 683 { 684 subroutineStarts[offset] = currentSubroutineStart; 686 } 687 } 688 } 689 | Popular Tags |