1 /* 2 * ProGuard -- shrinking, optimization, obfuscation, and preverification 3 * of Java bytecode. 4 * 5 * Copyright (c) 2002-2014 Eric Lafortune (eric@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.classfile.util; 22 23 import proguard.classfile.*; 24 import proguard.classfile.attribute.CodeAttribute; 25 import proguard.classfile.constant.*; 26 import proguard.classfile.constant.visitor.ConstantVisitor; 27 import proguard.classfile.instruction.*; 28 import proguard.classfile.instruction.visitor.InstructionVisitor; 29 30 import java.util.Arrays; 31 32 /** 33 * This InstructionVisitor checks whether a given pattern instruction sequence 34 * occurs in the instructions that are visited. The arguments of the 35 * instruction sequence can be wildcards that are matched. 36 * 37 * @author Eric Lafortune 38 */ 39 public class InstructionSequenceMatcher 40 extends SimplifiedVisitor 41 implements InstructionVisitor, 42 ConstantVisitor 43 { 44 //* 45 private static final boolean DEBUG = false; 46 private static final boolean DEBUG_MORE = false; 47 /*/ 48 public static boolean DEBUG = true; 49 public static boolean DEBUG_MORE = true; 50 //*/ 51 52 public static final int X = 0x40000000; 53 public static final int Y = 0x40000001; 54 public static final int Z = 0x40000002; 55 56 public static final int A = 0x40000003; 57 public static final int B = 0x40000004; 58 public static final int C = 0x40000005; 59 public static final int D = 0x40000006; 60 61 62 private final Constant[] patternConstants; 63 private final Instruction[] patternInstructions; 64 65 private boolean matching; 66 private int patternInstructionIndex; 67 private final int[] matchedInstructionOffsets; 68 private int matchedArgumentFlags; 69 private final int[] matchedArguments = new int[7]; 70 private final long[] matchedConstantFlags; 71 private final int[] matchedConstantIndices; 72 private int constantFlags; 73 private int previousConstantFlags; 74 75 // Fields acting as a parameter and a return value for visitor methods. 76 private Constant patternConstant; 77 private boolean matchingConstant; 78 79 80 /** 81 * Creates a new InstructionSequenceMatcher. 82 * @param patternConstants any constants referenced by the pattern 83 * instruction. 84 * @param patternInstructions the pattern instruction sequence. 85 */ InstructionSequenceMatcher(Constant[] patternConstants, Instruction[] patternInstructions)86 public InstructionSequenceMatcher(Constant[] patternConstants, 87 Instruction[] patternInstructions) 88 { 89 this.patternConstants = patternConstants; 90 this.patternInstructions = patternInstructions; 91 92 matchedInstructionOffsets = new int[patternInstructions.length]; 93 matchedConstantFlags = new long[(patternConstants.length + 63) / 64]; 94 matchedConstantIndices = new int[patternConstants.length]; 95 } 96 97 98 /** 99 * Starts matching from the first instruction again next time. 100 */ reset()101 public void reset() 102 { 103 patternInstructionIndex = 0; 104 matchedArgumentFlags = 0; 105 106 Arrays.fill(matchedConstantFlags, 0L); 107 108 previousConstantFlags = constantFlags; 109 constantFlags = 0; 110 } 111 112 113 /** 114 * Returns whether the complete pattern sequence has been matched. 115 */ isMatching()116 public boolean isMatching() 117 { 118 return matching; 119 } 120 121 122 /** 123 * Returns the number of instructions in the pattern sequence. 124 */ instructionCount()125 public int instructionCount() 126 { 127 return patternInstructions.length; 128 } 129 130 131 /** 132 * Returns the matched instruction offset of the specified pattern 133 * instruction. 134 */ matchedInstructionOffset(int index)135 public int matchedInstructionOffset(int index) 136 { 137 return matchedInstructionOffsets[index]; 138 } 139 140 141 /** 142 * Returns whether the specified wildcard argument was a constant from 143 * the constant pool in the most recent match. 144 */ wasConstant(int argument)145 public boolean wasConstant(int argument) 146 { 147 return (previousConstantFlags & (1 << (argument - X))) != 0; 148 } 149 150 151 /** 152 * Returns the value of the specified matched argument (wildcard or not). 153 */ matchedArgument(int argument)154 public int matchedArgument(int argument) 155 { 156 int argumentIndex = argument - X; 157 return argumentIndex < 0 ? 158 argument : 159 matchedArguments[argumentIndex]; 160 } 161 162 163 /** 164 * Returns the values of the specified matched arguments (wildcard or not). 165 */ matchedArguments(int[] arguments)166 public int[] matchedArguments(int[] arguments) 167 { 168 int[] matchedArguments = new int[arguments.length]; 169 170 for (int index = 0; index < arguments.length; index++) 171 { 172 matchedArguments[index] = matchedArgument(arguments[index]); 173 } 174 175 return matchedArguments; 176 } 177 178 179 /** 180 * Returns the index of the specified matched constant (wildcard or not). 181 */ matchedConstantIndex(int constantIndex)182 public int matchedConstantIndex(int constantIndex) 183 { 184 int argumentIndex = constantIndex - X; 185 return argumentIndex < 0 ? 186 matchedConstantIndices[constantIndex] : 187 matchedArguments[argumentIndex]; 188 } 189 190 191 /** 192 * Returns the value of the specified matched branch offset (wildcard or 193 * not). 194 */ matchedBranchOffset(int offset, int branchOffset)195 public int matchedBranchOffset(int offset, int branchOffset) 196 { 197 int argumentIndex = branchOffset - X; 198 return argumentIndex < 0 ? 199 branchOffset : 200 matchedArguments[argumentIndex] - offset; 201 } 202 203 204 /** 205 * Returns the values of the specified matched jump offsets (wildcard or 206 * not). 207 */ matchedJumpOffsets(int offset, int[] jumpOffsets)208 public int[] matchedJumpOffsets(int offset, int[] jumpOffsets) 209 { 210 int[] matchedJumpOffsets = new int[jumpOffsets.length]; 211 212 for (int index = 0; index < jumpOffsets.length; index++) 213 { 214 matchedJumpOffsets[index] = matchedBranchOffset(offset, 215 jumpOffsets[index]); 216 } 217 218 return matchedJumpOffsets; 219 } 220 221 222 // Implementations for InstructionVisitor. 223 visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)224 public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction) 225 { 226 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 227 228 // Check if the instruction matches the next instruction in the sequence. 229 boolean condition = 230 matchingOpcodes(simpleInstruction, patternInstruction) && 231 matchingArguments(simpleInstruction.constant, 232 ((SimpleInstruction)patternInstruction).constant); 233 234 // Check if the instruction sequence is matching now. 235 checkMatch(condition, 236 clazz, 237 method, 238 codeAttribute, 239 offset, 240 simpleInstruction); 241 } 242 243 visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)244 public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction) 245 { 246 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 247 248 // Check if the instruction matches the next instruction in the sequence. 249 boolean condition = 250 matchingOpcodes(variableInstruction, patternInstruction) && 251 matchingArguments(variableInstruction.variableIndex, 252 ((VariableInstruction)patternInstruction).variableIndex) && 253 matchingArguments(variableInstruction.constant, 254 ((VariableInstruction)patternInstruction).constant); 255 256 // Check if the instruction sequence is matching now. 257 checkMatch(condition, 258 clazz, 259 method, 260 codeAttribute, 261 offset, 262 variableInstruction); 263 } 264 265 visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)266 public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction) 267 { 268 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 269 270 // Check if the instruction matches the next instruction in the sequence. 271 boolean condition = 272 matchingOpcodes(constantInstruction, patternInstruction) && 273 matchingConstantIndices(clazz, 274 constantInstruction.constantIndex, 275 ((ConstantInstruction)patternInstruction).constantIndex) && 276 matchingArguments(constantInstruction.constant, 277 ((ConstantInstruction)patternInstruction).constant); 278 279 // Check if the instruction sequence is matching now. 280 checkMatch(condition, 281 clazz, 282 method, 283 codeAttribute, 284 offset, 285 constantInstruction); 286 } 287 288 visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)289 public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction) 290 { 291 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 292 293 // Check if the instruction matches the next instruction in the from 294 // sequence. 295 boolean condition = 296 matchingOpcodes(branchInstruction, patternInstruction) && 297 matchingBranchOffsets(offset, 298 branchInstruction.branchOffset, 299 ((BranchInstruction)patternInstruction).branchOffset); 300 301 // Check if the instruction sequence is matching now. 302 checkMatch(condition, 303 clazz, 304 method, 305 codeAttribute, 306 offset, 307 branchInstruction); 308 } 309 310 visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)311 public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction) 312 { 313 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 314 315 // Check if the instruction matches the next instruction in the sequence. 316 boolean condition = 317 matchingOpcodes(tableSwitchInstruction, patternInstruction) && 318 matchingBranchOffsets(offset, 319 tableSwitchInstruction.defaultOffset, 320 ((TableSwitchInstruction)patternInstruction).defaultOffset) && 321 matchingArguments(tableSwitchInstruction.lowCase, 322 ((TableSwitchInstruction)patternInstruction).lowCase) && 323 matchingArguments(tableSwitchInstruction.highCase, 324 ((TableSwitchInstruction)patternInstruction).highCase) && 325 matchingJumpOffsets(offset, 326 tableSwitchInstruction.jumpOffsets, 327 ((TableSwitchInstruction)patternInstruction).jumpOffsets); 328 329 // Check if the instruction sequence is matching now. 330 checkMatch(condition, 331 clazz, 332 method, 333 codeAttribute, 334 offset, 335 tableSwitchInstruction); 336 } 337 338 visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)339 public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction) 340 { 341 Instruction patternInstruction = patternInstructions[patternInstructionIndex]; 342 343 // Check if the instruction matches the next instruction in the sequence. 344 boolean condition = 345 matchingOpcodes(lookUpSwitchInstruction, patternInstruction) && 346 matchingBranchOffsets(offset, 347 lookUpSwitchInstruction.defaultOffset, 348 ((LookUpSwitchInstruction)patternInstruction).defaultOffset) && 349 matchingArguments(lookUpSwitchInstruction.cases, 350 ((LookUpSwitchInstruction)patternInstruction).cases) && 351 matchingJumpOffsets(offset, 352 lookUpSwitchInstruction.jumpOffsets, 353 ((LookUpSwitchInstruction)patternInstruction).jumpOffsets); 354 355 // Check if the instruction sequence is matching now. 356 checkMatch(condition, 357 clazz, 358 method, 359 codeAttribute, 360 offset, 361 lookUpSwitchInstruction); 362 } 363 364 365 // Implementations for ConstantVisitor. 366 visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)367 public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant) 368 { 369 IntegerConstant integerPatternConstant = (IntegerConstant)patternConstant; 370 371 // Compare the integer values. 372 matchingConstant = integerConstant.getValue() == 373 integerPatternConstant.getValue(); 374 } 375 376 visitLongConstant(Clazz clazz, LongConstant longConstant)377 public void visitLongConstant(Clazz clazz, LongConstant longConstant) 378 { 379 LongConstant longPatternConstant = (LongConstant)patternConstant; 380 381 // Compare the long values. 382 matchingConstant = longConstant.getValue() == 383 longPatternConstant.getValue(); 384 } 385 386 visitFloatConstant(Clazz clazz, FloatConstant floatConstant)387 public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant) 388 { 389 FloatConstant floatPatternConstant = (FloatConstant)patternConstant; 390 391 // Compare the float values. 392 matchingConstant = floatConstant.getValue() == 393 floatPatternConstant.getValue(); 394 } 395 396 visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)397 public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant) 398 { 399 DoubleConstant doublePatternConstant = (DoubleConstant)patternConstant; 400 401 // Compare the double values. 402 matchingConstant = doubleConstant.getValue() == 403 doublePatternConstant.getValue(); 404 } 405 406 visitStringConstant(Clazz clazz, StringConstant stringConstant)407 public void visitStringConstant(Clazz clazz, StringConstant stringConstant) 408 { 409 StringConstant stringPatternConstant = (StringConstant)patternConstant; 410 411 // Check the UTF-8 constant. 412 matchingConstant = 413 matchingConstantIndices(clazz, 414 stringConstant.u2stringIndex, 415 stringPatternConstant.u2stringIndex); 416 } 417 418 visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)419 public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant) 420 { 421 Utf8Constant utf8PatternConstant = (Utf8Constant)patternConstant; 422 423 // Compare the actual strings. 424 matchingConstant = utf8Constant.getString().equals( 425 utf8PatternConstant.getString()); 426 } 427 428 visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant)429 public void visitInvokeDynamicConstant(Clazz clazz, InvokeDynamicConstant invokeDynamicConstant) 430 { 431 InvokeDynamicConstant invokeDynamicPatternConstant = (InvokeDynamicConstant)patternConstant; 432 433 // Check the bootstrap method and the name and type. 434 matchingConstant = 435 matchingConstantIndices(clazz, 436 invokeDynamicConstant.getBootstrapMethodAttributeIndex(), 437 invokeDynamicPatternConstant.getBootstrapMethodAttributeIndex()) && 438 matchingConstantIndices(clazz, 439 invokeDynamicConstant.getNameAndTypeIndex(), 440 invokeDynamicPatternConstant.getNameAndTypeIndex()); 441 } 442 443 visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant)444 public void visitMethodHandleConstant(Clazz clazz, MethodHandleConstant methodHandleConstant) 445 { 446 MethodHandleConstant methodHandlePatternConstant = (MethodHandleConstant)patternConstant; 447 448 // Check the handle type and the name and type. 449 matchingConstant = 450 matchingArguments(methodHandleConstant.getReferenceKind(), 451 methodHandlePatternConstant.getReferenceKind()) && 452 matchingConstantIndices(clazz, 453 methodHandleConstant.getReferenceIndex(), 454 methodHandlePatternConstant.getReferenceIndex()); 455 } 456 457 visitAnyRefConstant(Clazz clazz, RefConstant refConstant)458 public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant) 459 { 460 RefConstant refPatternConstant = (RefConstant)patternConstant; 461 462 // Check the class and the name and type. 463 matchingConstant = 464 matchingConstantIndices(clazz, 465 refConstant.getClassIndex(), 466 refPatternConstant.getClassIndex()) && 467 matchingConstantIndices(clazz, 468 refConstant.getNameAndTypeIndex(), 469 refPatternConstant.getNameAndTypeIndex()); 470 } 471 472 visitClassConstant(Clazz clazz, ClassConstant classConstant)473 public void visitClassConstant(Clazz clazz, ClassConstant classConstant) 474 { 475 ClassConstant classPatternConstant = (ClassConstant)patternConstant; 476 477 // Check the class name. 478 matchingConstant = 479 matchingConstantIndices(clazz, 480 classConstant.u2nameIndex, 481 classPatternConstant.u2nameIndex); 482 } 483 484 visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant)485 public void visitMethodTypeConstant(Clazz clazz, MethodTypeConstant methodTypeConstant) 486 { 487 MethodTypeConstant typePatternConstant = (MethodTypeConstant)patternConstant; 488 489 // Check the descriptor. 490 matchingConstant = 491 matchingConstantIndices(clazz, 492 methodTypeConstant.u2descriptorIndex, 493 typePatternConstant.u2descriptorIndex); 494 } 495 496 visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)497 public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant) 498 { 499 NameAndTypeConstant typePatternConstant = (NameAndTypeConstant)patternConstant; 500 501 // Check the name and the descriptor. 502 matchingConstant = 503 matchingConstantIndices(clazz, 504 nameAndTypeConstant.u2nameIndex, 505 typePatternConstant.u2nameIndex) && 506 matchingConstantIndices(clazz, 507 nameAndTypeConstant.u2descriptorIndex, 508 typePatternConstant.u2descriptorIndex); 509 } 510 511 512 // Small utility methods. 513 matchingOpcodes(Instruction instruction1, Instruction instruction2)514 private boolean matchingOpcodes(Instruction instruction1, 515 Instruction instruction2) 516 { 517 // Check the opcode. 518 return instruction1.opcode == instruction2.opcode || 519 instruction1.canonicalOpcode() == instruction2.opcode; 520 } 521 522 matchingArguments(int argument1, int argument2)523 private boolean matchingArguments(int argument1, 524 int argument2) 525 { 526 int argumentIndex = argument2 - X; 527 if (argumentIndex < 0) 528 { 529 // Check the literal argument. 530 return argument1 == argument2; 531 } 532 else if (!isMatchingArgumentIndex(argumentIndex)) 533 { 534 // Store the wildcard argument. 535 setMatchingArgument(argumentIndex, argument1); 536 537 return true; 538 } 539 else 540 { 541 // Check the previously stored wildcard argument. 542 return matchedArguments[argumentIndex] == argument1; 543 } 544 } 545 546 547 /** 548 * Marks the specified argument (by index) as matching the specified 549 * argument value. 550 */ setMatchingArgument(int argumentIndex, int argument)551 private void setMatchingArgument(int argumentIndex, 552 int argument) 553 { 554 matchedArguments[argumentIndex] = argument; 555 matchedArgumentFlags |= 1 << argumentIndex; 556 } 557 558 559 /** 560 * Returns whether the specified wildcard argument (by index) has been 561 * matched. 562 */ isMatchingArgumentIndex(int argumentIndex)563 private boolean isMatchingArgumentIndex(int argumentIndex) 564 { 565 return (matchedArgumentFlags & (1 << argumentIndex)) != 0; 566 } 567 568 matchingArguments(int[] arguments1, int[] arguments2)569 private boolean matchingArguments(int[] arguments1, 570 int[] arguments2) 571 { 572 if (arguments1.length != arguments2.length) 573 { 574 return false; 575 } 576 577 for (int index = 0; index < arguments1.length; index++) 578 { 579 if (!matchingArguments(arguments1[index], arguments2[index])) 580 { 581 return false; 582 } 583 } 584 585 return true; 586 } 587 588 matchingConstantIndices(Clazz clazz, int constantIndex1, int constantIndex2)589 private boolean matchingConstantIndices(Clazz clazz, 590 int constantIndex1, 591 int constantIndex2) 592 { 593 if (constantIndex2 >= X) 594 { 595 // Remember that we are trying to match a constant. 596 constantFlags |= 1 << (constantIndex2 - X); 597 598 // Check the constant index. 599 return matchingArguments(constantIndex1, constantIndex2); 600 } 601 else if (!isMatchingConstantIndex(constantIndex2)) 602 { 603 // Check the actual constant. 604 matchingConstant = false; 605 patternConstant = patternConstants[constantIndex2]; 606 607 if (clazz.getTag(constantIndex1) == patternConstant.getTag()) 608 { 609 clazz.constantPoolEntryAccept(constantIndex1, this); 610 611 if (matchingConstant) 612 { 613 // Store the constant index. 614 setMatchingConstant(constantIndex2, constantIndex1); 615 } 616 } 617 618 return matchingConstant; 619 } 620 else 621 { 622 // Check a previously stored constant index. 623 return matchedConstantIndices[constantIndex2] == constantIndex1; 624 } 625 } 626 627 628 /** 629 * Marks the specified constant (by index) as matching the specified 630 * constant index value. 631 */ setMatchingConstant(int constantIndex, int constantIndex1)632 private void setMatchingConstant(int constantIndex, 633 int constantIndex1) 634 { 635 matchedConstantIndices[constantIndex] = constantIndex1; 636 matchedConstantFlags[constantIndex / 64] |= 1L << constantIndex; 637 } 638 639 640 /** 641 * Returns whether the specified wildcard constant has been matched. 642 */ isMatchingConstantIndex(int constantIndex)643 private boolean isMatchingConstantIndex(int constantIndex) 644 { 645 return (matchedConstantFlags[constantIndex / 64] & (1L << constantIndex)) != 0; 646 } 647 648 matchingBranchOffsets(int offset, int branchOffset1, int branchOffset2)649 private boolean matchingBranchOffsets(int offset, 650 int branchOffset1, 651 int branchOffset2) 652 { 653 int argumentIndex = branchOffset2 - X; 654 if (argumentIndex < 0) 655 { 656 // Check the literal argument. 657 return branchOffset1 == branchOffset2; 658 } 659 else if (!isMatchingArgumentIndex(argumentIndex)) 660 { 661 // Store a wildcard argument. 662 setMatchingArgument(argumentIndex, offset + branchOffset1); 663 664 return true; 665 } 666 else 667 { 668 // Check the previously stored wildcard argument. 669 return matchedArguments[argumentIndex] == offset + branchOffset1; 670 } 671 } 672 673 matchingJumpOffsets(int offset, int[] jumpOffsets1, int[] jumpOffsets2)674 private boolean matchingJumpOffsets(int offset, 675 int[] jumpOffsets1, 676 int[] jumpOffsets2) 677 { 678 if (jumpOffsets1.length != jumpOffsets2.length) 679 { 680 return false; 681 } 682 683 for (int index = 0; index < jumpOffsets1.length; index++) 684 { 685 if (!matchingBranchOffsets(offset, 686 jumpOffsets1[index], 687 jumpOffsets2[index])) 688 { 689 return false; 690 } 691 } 692 693 return true; 694 } 695 696 checkMatch(boolean condition, Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)697 private void checkMatch(boolean condition, 698 Clazz clazz, 699 Method method, 700 CodeAttribute codeAttribute, 701 int offset, 702 Instruction instruction) 703 { 704 if (DEBUG_MORE) 705 { 706 System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]: "+patternInstructions[patternInstructionIndex].toString(patternInstructionIndex)+(condition?"\t== ":"\t ")+instruction.toString(offset)); 707 } 708 709 // Did the instruction match? 710 if (condition) 711 { 712 // Remember the offset of the matching instruction. 713 matchedInstructionOffsets[patternInstructionIndex] = offset; 714 715 // Try to match the next instruction next time. 716 patternInstructionIndex++; 717 718 // Did we match all instructions in the sequence? 719 matching = patternInstructionIndex == patternInstructions.length; 720 721 if (matching) 722 { 723 if (DEBUG) 724 { 725 System.out.println("InstructionSequenceMatcher: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]"); 726 for (int index = 0; index < patternInstructionIndex; index++) 727 { 728 System.out.println(" "+InstructionFactory.create(codeAttribute.code, matchedInstructionOffsets[index]).toString(matchedInstructionOffsets[index])); 729 } 730 } 731 732 // Start matching from the first instruction again next time. 733 reset(); 734 } 735 } 736 else 737 { 738 // The instruction didn't match. 739 matching = false; 740 741 // Is this a failed second instruction? 742 boolean retry = patternInstructionIndex == 1; 743 744 // Start matching from the first instruction next time. 745 reset(); 746 747 // Retry a failed second instruction as a first instruction. 748 if (retry) 749 { 750 instruction.accept(clazz, method, codeAttribute, offset, this); 751 } 752 } 753 } 754 } 755