KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > alt > jiapi > reflect > SwitchInstruction


1 package alt.jiapi.reflect;
2
3 import java.io.ByteArrayOutputStream JavaDoc;
4
5 import alt.jiapi.reflect.Instruction;
6 import alt.jiapi.reflect.instruction.Opcodes;
7
8 /**
9  * SwitchInstruction represents switch-case construct
10  * in Java language jargon. Internally, this class encapsulates
11  * different switch instructions in bytecode level. Like
12  * tableswitch and lookupswitch.
13  *
14  * @author Mika Riekkinen
15  */

16 public class SwitchInstruction extends Instruction {
17     private Instruction deflt;
18     private Instruction[] targets;
19     
20     // these are constructed in constructor, and are valid
21
// only in InstructionParser creation loop.
22
// Once this loop is done, privatees above are valid,
23
// and privatees below are not used anymore.
24
private int padding;
25     private int defaultOffset;
26     private int nPairs;
27
28     private int[] keys;
29     private int[] targetOffsets;
30
31     /*
32      * NOTE1: We do not have public constructors.
33      *
34      * If we create public constructors, it should be something like
35      * SwitchInstruction(Instruction default, int[]keys,
36      * Instruction[] targets);
37      *
38      * NOTE2: Should we keep targets in a List instead.
39      * developer could add into this list new targets at will.
40      * What about keys??? Should opcode be forced to lookupswitch ???
41      */

42
43 // SwitchInstruction(byte[] bytes) {
44
// super(bytes);
45
// }
46

47     SwitchInstruction(byte[] bytes, int padding, int nPairs) {
48         super(bytes);
49         this.padding = padding;
50         this.defaultOffset = toInt(bytes, 1 + padding);
51         this.nPairs = nPairs;
52         
53         this.keys = new int[nPairs];
54         this.targetOffsets = new int[nPairs];
55
56         if (bytes[0] == Opcodes.LOOKUPSWITCH) {
57             // process lookupswitch
58

59             for (int i = 0; i < keys.length; i++) {
60                 int start = (1 + padding + 8) + (i*4*2);
61                 keys[i] = toInt(bytes, start);
62             }
63             
64             for (int i = 0; i < targetOffsets.length; i++) {
65                 int start = (1 + padding + 8) + (i*4*2) + 4;
66                 targetOffsets[i] = toInt(bytes, start);
67             }
68         }
69         else {
70             // process tableswitch
71

72             int low = toInt(bytes, padding + 5);
73             int high = toInt(bytes, padding + 9);
74
75             for (int i = low; i < high /* +1 ??? */; i++) {
76                 keys[i] = i;
77             }
78
79             for (int i = 0; i < targetOffsets.length; i++) {
80                 int start = (padding + 13) + (i*4);
81                 targetOffsets[i] = toInt(bytes, start);
82             }
83         }
84     }
85
86     /**
87      * Get the default Instruction of this SwitchInstruction.
88      * Default instruction is the one used, when keys do not match.
89      *
90      * @return default Instruction of this SwitchInstruction
91      */

92     public Instruction getDefault() {
93         return deflt;
94     }
95
96     /**
97      * Gets all the targets of this SwitchInstruction.
98      * Target encapsulates target Instruction, and its associated key.
99      *
100      * @return an array of Targets.
101      */

102     public Target[] getTargets() {
103         Target[] __targets = new Target[targets.length];
104         for (int i = 0; i < __targets.length; i++) {
105             __targets[i] = new Target(keys[i], targets[i]);
106         }
107
108         return __targets;
109     }
110
111     /**
112      * Gets all the targets of this SwitchInstruction.
113      *
114      * @return An array of target Instructions
115      * NOTE: This method is not used
116      */

117     private Instruction[] __getTargets() {
118         return targets;
119     }
120
121     /**
122      * Gets the keys of this SwitchInstruction.
123      * @see #getTargets()
124      * NOTE: This method is not used
125      */

126     private int[] __getKeys() {
127         return keys;
128     }
129
130     public String JavaDoc toString() {
131         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(super.toString());
132         sb.append(", default:");
133         sb.append(getDefault());
134         sb.append("(offset:");
135         sb.append(getDefault().getOffset());
136         sb.append(")");
137         sb.append(", ");
138
139         Target[] t = getTargets();
140         for (int i = 0; i < t.length; i++) {
141             sb.append("{");
142             sb.append(t[i].getKey());
143             sb.append(":");
144             sb.append(t[i].getTarget());
145              sb.append("(offset:");
146              sb.append(t[i].getTarget().getOffset());
147              sb.append(")");
148             sb.append("}");
149         }
150
151         return sb.toString();
152     }
153
154
155
156
157
158     public byte[] getBytes() {
159         byte[] bytes = super.getBytes();
160         int offset = getOffset();
161
162         ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc();
163         baos.write(getOpcode());
164
165
166         int pCount = 3 - (offset % 4);
167         for (int i = 0; i < pCount; i++) {
168             baos.write(0); // Padding
169
}
170
171
172         // default:
173
int dOffset = getDefault().getOffset();
174         byte[] dBytes = toBytes(dOffset - offset - pCount -1 );
175         for (int i = 0; i < dBytes.length; i++) {
176             baos.write(dBytes[i]);
177         }
178
179
180         if (getOpcode() == Opcodes.LOOKUPSWITCH) {
181             // for lookupswitch: -----------------
182

183             // npairs:
184
byte[] np = toBytes(targets.length);
185             for (int i = 0; i < np.length; i++) {
186                 baos.write(np[i]);
187             }
188             
189             // pairs
190
for (int i = 0; i < targets.length; i++) {
191                 try {
192                     baos.write(toBytes(keys[i]));
193                     baos.write(toBytes(targets[i].getOffset() - offset -pCount-1));
194                 }
195                 catch(Exception JavaDoc e) {
196                     // Should not happen
197
}
198             }
199         }
200         else {
201             // for tableswitch: -----------------
202
int low = keys[0];
203             int high = keys[keys.length - 1];
204
205             // low, high:
206
try {
207                 baos.write(toBytes(low));
208                 baos.write(toBytes(high));
209             }
210             catch(Exception JavaDoc e) {
211                 // Should not happen
212
}
213
214             for (int i = 0; i < targets.length; i++) {
215                 try {
216                     baos.write(toBytes(targets[i].getOffset() -
217                                        offset - pCount - 1));
218                 }
219                 catch(Exception JavaDoc e) {
220                     // Should not happen
221
}
222             }
223         }
224
225         byte[] __bytes = baos.toByteArray();
226         return __bytes;
227     }
228
229
230     /**
231      * Used by InstructionParser
232      */

233     int getDefaultOffset() {
234         return defaultOffset;
235     }
236
237     /**
238      * Used by InstructionParser
239      */

240     void setDefault(Instruction deflt) {
241         this.deflt = deflt;
242     }
243
244     /**
245      * Used by InstructionParser
246      */

247     int[] getTargetOffsets() {
248         return targetOffsets;
249     }
250
251     /**
252      * Used by InstructionParser
253      */

254     void setTargets(Instruction[] targets) {
255         this.targets = targets;
256     }
257
258
259     /*
260      * We should collect these methods in some utility class.
261      */

262     int toInt(byte[] bytes, int start) {
263         byte b1 = bytes[start];
264         byte b2 = bytes[start + 1];
265         byte b3 = bytes[start + 2];
266         byte b4 = bytes[start + 3];
267
268         int i = (b1 << 24) & 0xff000000 | (b2 << 16) & 0xff0000|
269             (b3 << 8) & 0xff00 | (b4 & 0xff);
270
271         return i;
272     }
273
274     /*
275      */

276     byte[] toBytes(int i) {
277         byte [] bytes = new byte[4];
278
279         bytes[0] = (byte)((i >> 24) & 0xff);
280         bytes[1] = (byte)((i >> 16) & 0xff);
281         bytes[2] = (byte)((i >> 8) & 0xff);
282         bytes[3] = (byte)((i & 0xff));
283         
284         return bytes;
285     }
286
287
288     /**
289      * This class encapsulates SwitchInstructions key-target pair.
290      */

291     public class Target {
292         private int key;
293         private Instruction target;
294
295         Target(int key, Instruction target) {
296             this.key = key;
297             this.target = target;
298         }
299
300         /**
301          * Gets the key of this target.
302          */

303         public int getKey() {
304             return key;
305         }
306
307         /**
308          * Gets the target Instruction of this target.
309          */

310         public Instruction getTarget() {
311             return target;
312         }
313     }
314 }
315
Popular Tags