• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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