KickJava   Java API By Example, From Geeks To Geeks.

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


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.*;
24 import proguard.classfile.attribute.CodeAttribute;
25 import proguard.classfile.editor.CodeAttributeEditor;
26 import proguard.classfile.instruction.*;
27 import proguard.classfile.instruction.visitor.InstructionVisitor;
28 import proguard.classfile.util.SimplifiedVisitor;
29
30 /**
31  * This InstructionVisitor deletes all push/pop instruction pairs. In this
32  * context, push instructions are instructions that push values onto the stack,
33  * like dup and load instructions.
34  *
35  * @author Eric Lafortune
36  */

37 public class PushPopRemover
38 extends SimplifiedVisitor
39 implements InstructionVisitor
40 {
41     private BranchTargetFinder branchTargetFinder;
42     private CodeAttributeEditor codeAttributeEditor;
43     private InstructionVisitor extraInstructionVisitor;
44
45
46     /**
47      * Creates a new PushPopRemover.
48      * @param branchTargetFinder a branch target finder that has been
49      * initialized to indicate branch targets
50      * in the visited code.
51      * @param codeAttributeEditor a code editor that can be used for
52      * accumulating changes to the code.
53      */

54     public PushPopRemover(BranchTargetFinder branchTargetFinder,
55                           CodeAttributeEditor codeAttributeEditor)
56     {
57         this(branchTargetFinder, codeAttributeEditor, null);
58     }
59
60
61     /**
62      * Creates a new PushPopRemover.
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      * @param extraInstructionVisitor an optional extra visitor for all deleted
69      * push instructions.
70      */

71     public PushPopRemover(BranchTargetFinder branchTargetFinder,
72                           CodeAttributeEditor codeAttributeEditor,
73                           InstructionVisitor extraInstructionVisitor)
74     {
75         this.branchTargetFinder = branchTargetFinder;
76         this.codeAttributeEditor = codeAttributeEditor;
77         this.extraInstructionVisitor = extraInstructionVisitor;
78     }
79
80
81     // Implementations for InstructionVisitor.
82

83     public void visitAnyInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, Instruction instruction) {}
84
85
86     public void visitSimpleInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SimpleInstruction simpleInstruction)
87     {
88         switch (simpleInstruction.opcode)
89         {
90             case InstructionConstants.OP_ICONST_M1:
91             case InstructionConstants.OP_ICONST_0:
92             case InstructionConstants.OP_ICONST_1:
93             case InstructionConstants.OP_ICONST_2:
94             case InstructionConstants.OP_ICONST_3:
95             case InstructionConstants.OP_ICONST_4:
96             case InstructionConstants.OP_ICONST_5:
97             case InstructionConstants.OP_LCONST_0:
98             case InstructionConstants.OP_LCONST_1:
99             case InstructionConstants.OP_FCONST_0:
100             case InstructionConstants.OP_FCONST_1:
101             case InstructionConstants.OP_FCONST_2:
102             case InstructionConstants.OP_DCONST_0:
103             case InstructionConstants.OP_DCONST_1:
104
105             case InstructionConstants.OP_DUP:
106             case InstructionConstants.OP_DUP2:
107             case InstructionConstants.OP_BIPUSH:
108             case InstructionConstants.OP_SIPUSH:
109             case InstructionConstants.OP_LDC:
110             case InstructionConstants.OP_LDC_W:
111             case InstructionConstants.OP_LDC2_W:
112                 // All these simple instructions are pushing instructions.
113
deleteWithSubsequentPop(clazz, method, codeAttribute, offset, simpleInstruction);
114                 break;
115         }
116     }
117
118     public void visitVariableInstruction(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VariableInstruction variableInstruction)
119     {
120         if (variableInstruction.isLoad() &&
121             variableInstruction.opcode != InstructionConstants.OP_RET)
122         {
123             // All load instructions are pushing instructions.
124
deleteWithSubsequentPop(clazz, method, codeAttribute, offset, variableInstruction);
125         }
126     }
127
128
129     // Small utility methods.
130

131     /**
132      * Deletes the given instruction and its subsequent compatible pop instruction,
133      * if any, and if the latter is not a branch target.
134      */

135     private void deleteWithSubsequentPop(Clazz clazz,
136                                          Method method,
137                                          CodeAttribute codeAttribute,
138                                          int offset,
139                                          Instruction instruction)
140     {
141         boolean isCategory2 = instruction.isCategory2();
142
143         int nextOffset = offset + instruction.length(offset);
144
145         if (!codeAttributeEditor.isModified(offset) &&
146             !codeAttributeEditor.isModified(nextOffset) &&
147             !branchTargetFinder.isTarget(nextOffset))
148         {
149             Instruction nextInstruction = InstructionFactory.create(codeAttribute.code,
150                                                                     nextOffset);
151             int nextOpcode = nextInstruction.opcode;
152             if ((nextOpcode == InstructionConstants.OP_POP ||
153                  nextOpcode == InstructionConstants.OP_POP2) &&
154                                                              nextInstruction.isCategory2() == isCategory2)
155             {
156                 // Delete the pushing instruction and the pop instruction.
157
codeAttributeEditor.deleteInstruction(offset);
158                 codeAttributeEditor.deleteInstruction(nextOffset);
159
160                 // Visit the instruction, if required.
161
if (extraInstructionVisitor != null)
162                 {
163                     instruction.accept(clazz, method, codeAttribute, offset, extraInstructionVisitor);
164                 }
165             }
166         }
167     }
168 }
169
Popular Tags