KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > optimize > peephole > InstructionSequenceReplacer


1 /*
2  * ProGuard -- shrinking, optimization, obfuscation, and preverification
3  * of Java bytecode.
4  *
5  * Copyright (c) 2002-2007 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.optimize.peephole;
22
23 import proguard.classfile.instruction.visitor.InstructionVisitor;
24 import proguard.classfile.instruction.*;
25 import proguard.classfile.editor.CodeAttributeEditor;
26 import proguard.classfile.*;
27 import proguard.classfile.util.*;
28 import proguard.classfile.constant.*;
29 import proguard.classfile.constant.visitor.ConstantVisitor;
30 import proguard.classfile.attribute.CodeAttribute;
31
32 /**
33  * This InstructionVisitor replaces a given pattern instruction sequence by
34  * another given replacement instruction sequence. The arguments of the
35  * instruction sequences can be wildcards that are matched and replaced.
36  *
37  * @see InstructionSequenceMatcher
38  * @author Eric Lafortune
39  */

40 public class InstructionSequenceReplacer
41 extends SimplifiedVisitor
42 implements InstructionVisitor,
43              ConstantVisitor
44 {
45     private static final boolean DEBUG = false;
46
47
48     private InstructionSequenceMatcher instructionSequenceMatcher;
49     private Instruction[] replacementInstructions;
50     private BranchTargetFinder branchTargetFinder;
51     private CodeAttributeEditor codeAttributeEditor;
52     private InstructionVisitor extraInstructionVisitor;
53
54     private MyReplacementInstructionFactory replacementInstructionFactory = new MyReplacementInstructionFactory();
55
56
57     /**
58      * Creates a new InstructionSequenceReplacer.
59      * @param patternConstants any constants referenced by the pattern
60      * instruction.
61      * @param patternInstructions the pattern instruction sequence.
62      * @param replacementInstructions the replacement instruction sequence.
63      * @param branchTargetFinder a branch target finder that has been
64      * initialized to indicate branch targets
65      * in the visited code.
66      * @param codeAttributeEditor a code editor that can be used for
67      * accumulating changes to the code.
68      */

69     public InstructionSequenceReplacer(Constant[] patternConstants,
70                                        Instruction[] patternInstructions,
71                                        Instruction[] replacementInstructions,
72                                        BranchTargetFinder branchTargetFinder,
73                                        CodeAttributeEditor codeAttributeEditor)
74     {
75         this(patternConstants,
76              patternInstructions,
77              replacementInstructions,
78              branchTargetFinder,
79              codeAttributeEditor,
80              null);
81     }
82
83
84     /**
85      * Creates a new InstructionSequenceReplacer.
86      * @param patternConstants any constants referenced by the pattern
87      * instruction.
88      * @param branchTargetFinder a branch target finder that has been
89      * initialized to indicate branch targets
90      * in the visited code.
91      * @param codeAttributeEditor a code editor that can be used for
92      * accumulating changes to the code.
93      * @param extraInstructionVisitor an optional extra visitor for all deleted
94      * load instructions.
95      */

96     public InstructionSequenceReplacer(Constant[] patternConstants,
97                                        Instruction[] patternInstructions,
98                                        Instruction[] replacementInstructions,
99                                        BranchTargetFinder branchTargetFinder,
100                                        CodeAttributeEditor codeAttributeEditor,
101                                        InstructionVisitor extraInstructionVisitor)
102     {
103         this.instructionSequenceMatcher = new InstructionSequenceMatcher(patternConstants, patternInstructions);
104         this.replacementInstructions = replacementInstructions;
105         this.branchTargetFinder = branchTargetFinder;
106         this.codeAttributeEditor = codeAttributeEditor;
107         this.extraInstructionVisitor = extraInstructionVisitor;
108     }
109
110
111     // Implementations for InstructionVisitor.
112

113     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction)
114     {
115         // Reset the instruction sequence matcher if the instruction is a branch
116
// target or if it has already been modified.
117
if (branchTargetFinder.isTarget(offset) ||
118             codeAttributeEditor.isModified(offset))
119         {
120             instructionSequenceMatcher.reset();
121         }
122
123         // Try to match the instruction.
124
instruction.accept(clazz, method, codeAttribute, offset, instructionSequenceMatcher);
125
126         // Did the instruction sequence match and is it still unmodified?
127
if (instructionSequenceMatcher.isMatching() &&
128             matchedInstructionsUnmodified())
129         {
130             if (DEBUG)
131             {
132                 System.out.println("InstructionSequenceReplacer: ["+clazz.getName()+"."+method.getName(clazz)+method.getDescriptor(clazz)+"]");
133                 System.out.println(" Matched:");
134                 for (int index = 0; index < instructionSequenceMatcher.instructionCount(); index++)
135                 {
136                     int matchedOffset = instructionSequenceMatcher.matchedInstructionOffset(index);
137                     System.out.println(" "+InstructionFactory.create(codeAttribute.code, matchedOffset).toString(matchedOffset));
138                 }
139                 System.out.println(" Replacement:");
140                  for (int index = 0; index < replacementInstructions.length; index++)
141                 {
142                     int matchedOffset = instructionSequenceMatcher.matchedInstructionOffset(index);
143                     System.out.println(" "+replacementInstructionFactory.create(index).toString(matchedOffset));
144                 }
145             }
146
147             // Replace the instruction sequence.
148
for (int index = 0; index < replacementInstructions.length; index++)
149             {
150                 codeAttributeEditor.replaceInstruction(instructionSequenceMatcher.matchedInstructionOffset(index),
151                                                        replacementInstructionFactory.create(index));
152             }
153
154             // Delete any remaining instructions in the from sequence.
155
for (int index = replacementInstructions.length; index < instructionSequenceMatcher.instructionCount(); index++)
156             {
157                 codeAttributeEditor.deleteInstruction(instructionSequenceMatcher.matchedInstructionOffset(index));
158             }
159
160             // Visit the instruction, if required.
161
if (extraInstructionVisitor != null)
162             {
163                 instruction.accept(clazz,
164                                    method,
165                                    codeAttribute,
166                                    offset,
167                                    extraInstructionVisitor);
168             }
169         }
170     }
171
172
173     // Small utility methods.
174

175     /**
176      * Returns whether the matched pattern instructions haven't been modified
177      * before.
178      */

179     private boolean matchedInstructionsUnmodified()
180     {
181         for (int index = 0; index < instructionSequenceMatcher.instructionCount(); index++)
182         {
183             if (codeAttributeEditor.isModified(instructionSequenceMatcher.matchedInstructionOffset(index)))
184             {
185                 return false;
186             }
187         }
188
189         return true;
190     }
191
192
193     /**
194      * This class creates replacement instructions for matched sequences, with
195      * any matched arguments filled out.
196      */

197     private class MyReplacementInstructionFactory
198     implements InstructionVisitor
199     {
200         private Instruction replacementInstruction;
201
202
203         /**
204          * Creates the replacement instruction for the given index in the
205          * instruction sequence.
206          */

207         public Instruction create(int index)
208         {
209             // Create the instruction.
210
replacementInstructions[index].accept(null,
211                                                   null,
212                                                   null,
213                                                   instructionSequenceMatcher.matchedInstructionOffset(index),
214                                                   this);
215
216             // Return it.
217
return replacementInstruction.shrink();
218         }
219
220
221         // Implementations for InstructionVisitor.
222

223         public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
224         {
225             replacementInstruction =
226                 new SimpleInstruction(simpleInstruction.opcode,
227                                       instructionSequenceMatcher.matchedArgument(simpleInstruction.constant));
228         }
229
230
231         public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
232         {
233             replacementInstruction =
234                 new VariableInstruction(variableInstruction.opcode,
235                                         instructionSequenceMatcher.matchedArgument(variableInstruction.variableIndex),
236                                         instructionSequenceMatcher.matchedArgument(variableInstruction.constant));
237         }
238
239
240         public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
241         {
242             replacementInstruction =
243                 new ConstantInstruction(constantInstruction.opcode,
244                                         instructionSequenceMatcher.matchedConstantIndex(constantInstruction.constantIndex),
245                                         instructionSequenceMatcher.matchedArgument(constantInstruction.constant));
246         }
247
248
249         public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
250         {
251             replacementInstruction =
252                 new BranchInstruction(branchInstruction.opcode,
253                                       instructionSequenceMatcher.matchedBranchOffset(offset,
254                                                           branchInstruction.branchOffset));
255         }
256
257
258         public void visitTableSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, TableSwitchInstruction tableSwitchInstruction)
259         {
260             replacementInstruction =
261                 new TableSwitchInstruction(tableSwitchInstruction.opcode,
262                                            instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.defaultOffset),
263                                            instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.lowCase),
264                                            instructionSequenceMatcher.matchedArgument(tableSwitchInstruction.highCase),
265                                            instructionSequenceMatcher.matchedJumpOffsets(offset,
266                                                               tableSwitchInstruction.jumpOffsets));
267
268         }
269
270
271         public void visitLookUpSwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LookUpSwitchInstruction lookUpSwitchInstruction)
272         {
273             replacementInstruction =
274                 new LookUpSwitchInstruction(lookUpSwitchInstruction.opcode,
275                                             instructionSequenceMatcher.matchedArgument(lookUpSwitchInstruction.defaultOffset),
276                                             instructionSequenceMatcher.matchedArguments(lookUpSwitchInstruction.cases),
277                                             instructionSequenceMatcher.matchedJumpOffsets(offset,
278                                                                lookUpSwitchInstruction.jumpOffsets));
279         }
280     }
281 }
282
Popular Tags