KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > proguard > classfile > instruction > BranchInstruction


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.classfile.instruction;
22
23 import proguard.classfile.*;
24 import proguard.classfile.instruction.visitor.InstructionVisitor;
25 import proguard.classfile.attribute.*;
26
27 /**
28  * This interface describes an instruction that branches to a given offset in
29  * the code.
30  *
31  * @author Eric Lafortune
32  */

33 public class BranchInstruction extends Instruction
34 {
35     public int branchOffset;
36
37
38     /**
39      * Creates an uninitialized BranchInstruction.
40      */

41     public BranchInstruction() {}
42
43
44     public BranchInstruction(byte opcode, int branchOffset)
45     {
46         this.opcode = opcode;
47         this.branchOffset = branchOffset;
48     }
49
50
51     /**
52      * Copies the given instruction into this instruction.
53      * @param branchInstruction the instruction to be copied.
54      * @return this instruction.
55      */

56     public BranchInstruction copy(BranchInstruction branchInstruction)
57     {
58         this.opcode = branchInstruction.opcode;
59         this.branchOffset = branchInstruction.branchOffset;
60
61         return this;
62     }
63
64
65     // Implementations for Instruction.
66

67     public byte canonicalOpcode()
68     {
69         // Remove the _w extension, if any.
70
switch (opcode)
71         {
72             case InstructionConstants.OP_GOTO_W: return InstructionConstants.OP_GOTO;
73
74             case InstructionConstants.OP_JSR_W: return InstructionConstants.OP_JSR;
75
76             default: return opcode;
77         }
78     }
79
80     public Instruction shrink()
81     {
82         // Do we need an ordinary branch or a wide branch?
83
if (requiredBranchOffsetSize() == 2)
84         {
85             // Can we replace the wide branch by an ordinary branch?
86
if (opcode == InstructionConstants.OP_GOTO_W)
87             {
88                 opcode = InstructionConstants.OP_GOTO;
89             }
90             else if (opcode == InstructionConstants.OP_JSR_W)
91             {
92                 opcode = InstructionConstants.OP_JSR;
93             }
94         }
95         else
96         {
97             // Can we replace the ordinary branch by a wide branch?
98
if (opcode == InstructionConstants.OP_GOTO)
99             {
100                 opcode = InstructionConstants.OP_GOTO_W;
101             }
102             else if (opcode == InstructionConstants.OP_JSR)
103             {
104                 opcode = InstructionConstants.OP_JSR_W;
105             }
106             else
107             {
108                 throw new IllegalArgumentException JavaDoc("Branch instruction can't be widened ("+this.toString()+")");
109             }
110         }
111
112         return this;
113     }
114
115     protected void readInfo(byte[] code, int offset)
116     {
117         branchOffset = readSignedValue(code, offset, branchOffsetSize());
118     }
119
120
121     protected void writeInfo(byte[] code, int offset)
122     {
123         if (requiredBranchOffsetSize() > branchOffsetSize())
124         {
125             throw new IllegalArgumentException JavaDoc("Instruction has invalid branch offset size ("+this.toString(offset)+")");
126         }
127
128         writeSignedValue(code, offset, branchOffset, branchOffsetSize());
129     }
130
131
132     public int length(int offset)
133     {
134         return 1 + branchOffsetSize();
135     }
136
137
138     public void accept(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, InstructionVisitor instructionVisitor)
139     {
140         instructionVisitor.visitBranchInstruction(clazz, method, codeAttribute, offset, this);
141     }
142
143
144     public String JavaDoc toString(int offset)
145     {
146         return "["+offset+"] "+toString()+" (target="+(offset+branchOffset)+")";
147     }
148
149
150     // Implementations for Object.
151

152     public String JavaDoc toString()
153     {
154         return getName()+" "+(branchOffset >= 0 ? "+" : "")+branchOffset;
155     }
156
157
158     // Small utility methods.
159

160     /**
161      * Returns the branch offset size for this instruction.
162      */

163     private int branchOffsetSize()
164     {
165         return opcode == InstructionConstants.OP_GOTO_W ||
166                opcode == InstructionConstants.OP_JSR_W ? 4 :
167                                                           2;
168     }
169
170
171     /**
172      * Computes the required branch offset size for this instruction's branch
173      * offset.
174      */

175     private int requiredBranchOffsetSize()
176     {
177         return branchOffset << 16 >> 16 == branchOffset ? 2 :
178                                                           4;
179     }
180 }
181
Popular Tags