KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > editor > InstructionWriter


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 library 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 library 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 Lesser General Public License
15  * for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with this library; if not, write to the Free Software Foundation,
19  * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20  */

21 package proguard.classfile.editor;
22
23 import proguard.classfile.instruction.*;
24 import proguard.classfile.instruction.visitor.InstructionVisitor;
25 import proguard.classfile.attribute.visitor.AttributeVisitor;
26 import proguard.classfile.attribute.CodeAttribute;
27 import proguard.classfile.*;
28 import proguard.classfile.util.SimplifiedVisitor;
29
30 /**
31  * This InstructionVisitor writes out the instructions that it visits,
32  * collecting instructions that have to be widened. As an AttributeVisitor,
33  * it then applies the collected changes. The process will be repeated
34  * recursively, if necessary.
35  *
36  * @author Eric Lafortune
37  */

38 public class InstructionWriter
39 extends SimplifiedVisitor
40 implements InstructionVisitor,
41              AttributeVisitor
42 {
43     private int codeLength;
44
45     private CodeAttributeEditor codeAttributeEditor;
46
47
48     /**
49      * Resets the accumulated code changes.
50      * @param codeLength the length of the code that will be edited next.
51      */

52     public void reset(int codeLength)
53     {
54         this.codeLength = codeLength;
55
56         // The code attribute editor has to be created lazily.
57
if (codeAttributeEditor != null)
58         {
59             codeAttributeEditor.reset(codeLength);
60         }
61     }
62
63
64     // Implementations for InstructionVisitor.
65

66     public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
67     {
68         // Try to write out the instruction.
69
// Simple instructions should always fit.
70
simpleInstruction.write(codeAttribute, offset);
71     }
72
73
74     public void visitConstantInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ConstantInstruction constantInstruction)
75     {
76         try
77         {
78             // Try to write out the instruction.
79
constantInstruction.write(codeAttribute, offset);
80         }
81         catch (IllegalArgumentException JavaDoc exception)
82         {
83             // Create a new constant instruction that will fit.
84
Instruction replacementInstruction =
85                 new ConstantInstruction(constantInstruction.opcode,
86                                         constantInstruction.constantIndex,
87                                         constantInstruction.constant).shrink();
88
89             replaceInstruction(offset, replacementInstruction);
90
91             // Write out a dummy constant instruction for now.
92
constantInstruction.constantIndex = 0;
93             constantInstruction.constant = 0;
94             constantInstruction.write(codeAttribute, offset);
95         }
96     }
97
98
99     public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
100     {
101         try
102         {
103             // Try to write out the instruction.
104
variableInstruction.write(codeAttribute, offset);
105         }
106         catch (IllegalArgumentException JavaDoc exception)
107         {
108             // Create a new variable instruction that will fit.
109
Instruction replacementInstruction =
110                 new VariableInstruction(variableInstruction.opcode,
111                                         variableInstruction.variableIndex,
112                                         variableInstruction.constant).shrink();
113
114             replaceInstruction(offset, replacementInstruction);
115
116             // Write out a dummy variable instruction for now.
117
variableInstruction.variableIndex = 0;
118             variableInstruction.constant = 0;
119             variableInstruction.write(codeAttribute, offset);
120         }
121     }
122
123
124     public void visitBranchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, BranchInstruction branchInstruction)
125     {
126         try
127         {
128             // Try to write out the instruction.
129
branchInstruction.write(codeAttribute, offset);
130         }
131         catch (IllegalArgumentException JavaDoc exception)
132         {
133             // Create a new unconditional branch that will fit.
134
Instruction replacementInstruction =
135                 new BranchInstruction(InstructionConstants.OP_GOTO_W,
136                                       branchInstruction.branchOffset);
137
138             // Create a new instruction that will fit.
139
switch (branchInstruction.opcode)
140             {
141                 default:
142                 {
143                     // Create a new branch instruction that will fit.
144
replacementInstruction =
145                         new BranchInstruction(branchInstruction.opcode,
146                                               branchInstruction.branchOffset).shrink();
147
148                     break;
149                 }
150
151                 // Some special cases, for which a wide branch doesn't exist.
152
case InstructionConstants.OP_IFEQ:
153                 case InstructionConstants.OP_IFNE:
154                 case InstructionConstants.OP_IFLT:
155                 case InstructionConstants.OP_IFGE:
156                 case InstructionConstants.OP_IFGT:
157                 case InstructionConstants.OP_IFLE:
158                 case InstructionConstants.OP_IFICMPEQ:
159                 case InstructionConstants.OP_IFICMPNE:
160                 case InstructionConstants.OP_IFICMPLT:
161                 case InstructionConstants.OP_IFICMPGE:
162                 case InstructionConstants.OP_IFICMPGT:
163                 case InstructionConstants.OP_IFICMPLE:
164                 case InstructionConstants.OP_IFACMPEQ:
165                 case InstructionConstants.OP_IFACMPNE:
166                 {
167                     // Insert the complementary conditional branch.
168
Instruction complementaryConditionalBranch =
169                         new BranchInstruction((byte)(((branchInstruction.opcode+1) ^ 1) - 1),
170                                               (1+2) + (1+4));
171
172                     insertBeforeInstruction(offset, complementaryConditionalBranch);
173
174                     // Create a new unconditional branch that will fit.
175
break;
176                 }
177
178                 case InstructionConstants.OP_IFNULL:
179                 case InstructionConstants.OP_IFNONNULL:
180                 {
181                     // Insert the complementary conditional branch.
182
Instruction complementaryConditionalBranch =
183                         new BranchInstruction((byte)(branchInstruction.opcode ^ 1),
184                                               (1+2) + (1+4));
185
186                     insertBeforeInstruction(offset, complementaryConditionalBranch);
187
188                     // Create a new unconditional branch that will fit.
189
break;
190                 }
191             }
192
193             replaceInstruction(offset, replacementInstruction);
194
195             // Write out a dummy branch instruction for now.
196
branchInstruction.branchOffset = 0;
197             branchInstruction.write(codeAttribute, offset);
198         }
199     }
200
201
202     public void visitAnySwitchInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SwitchInstruction switchInstruction)
203     {
204         // Try to write out the instruction.
205
// Switch instructions should always fit.
206
switchInstruction.write(codeAttribute, offset);
207     }
208
209
210     // Implementations for AttributeVisitor.
211

212     public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
213     {
214         // Avoid doing any work if nothing is changing anyway.
215
if (codeAttributeEditor != null)
216         {
217             // Apply the collected expansions.
218
codeAttributeEditor.visitCodeAttribute(clazz, method, codeAttribute);
219
220             // Clear the modifications for the next run.
221
codeAttributeEditor = null;
222         }
223     }
224
225
226     // Small utility methods.
227

228     /**
229      * Remembers to place the given instruction right before the instruction
230      * at the given offset.
231      */

232     private void insertBeforeInstruction(int instructionOffset, Instruction instruction)
233     {
234         ensureCodeAttributeEditor();
235
236         // Replace the instruction.
237
codeAttributeEditor.insertBeforeInstruction(instructionOffset, instruction);
238     }
239
240
241     /**
242      * Remembers to replace the instruction at the given offset by the given
243      * instruction.
244      */

245     private void replaceInstruction(int instructionOffset, Instruction instruction)
246     {
247         ensureCodeAttributeEditor();
248
249         // Replace the instruction.
250
codeAttributeEditor.replaceInstruction(instructionOffset, instruction);
251     }
252
253
254     /**
255      * Remembers to place the given instruction right after the instruction
256      * at the given offset.
257      */

258     private void insertAfterInstruction(int instructionOffset, Instruction instruction)
259     {
260         ensureCodeAttributeEditor();
261
262         // Replace the instruction.
263
codeAttributeEditor.insertAfterInstruction(instructionOffset, instruction);
264     }
265
266
267     /**
268      * Makes sure there is a code attribute editor for the given code attribute.
269      */

270     private void ensureCodeAttributeEditor()
271     {
272         if (codeAttributeEditor == null)
273         {
274             codeAttributeEditor = new CodeAttributeEditor();
275             codeAttributeEditor.reset(codeLength);
276         }
277     }
278 }
279
Popular Tags