KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > edu > umd > cs > findbugs > ba > BytecodeScanner


1 /*
2  * Bytecode Analysis Framework
3  * Copyright (C) 2003,2004 University of Maryland
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18  */

19
20 package edu.umd.cs.findbugs.ba;
21
22 import edu.umd.cs.findbugs.SystemProperties;
23
24 /**
25  * Scan the raw bytecodes of a method.
26  * This is useful in order to find out quickly whether or not
27  * a method uses particular instructions.
28  *
29  * @author David Hovemeyer
30  */

31 public class BytecodeScanner implements org.apache.bcel.Constants {
32     private static final boolean DEBUG = SystemProperties.getBoolean("bs.debug");
33
34     /**
35      * Callback interface to report scanned instructions.
36      */

37     public interface Callback {
38         /**
39          * Called to indicate that a particular bytecode has been scanned.
40          *
41          * @param opcode the opcode of the instruction
42          * @param index the bytecode offset of the instruction
43          */

44         public void handleInstruction(int opcode, int index);
45     }
46
47     /**
48      * Convert the unsigned value of a byte into a short.
49      *
50      * @param value the byte
51      * @return the byte's unsigned value as a short
52      */

53     private static short unsignedValueOf(byte value) {
54         short result;
55         if ((value & 0x80) != 0) {
56             result = (short) (value & 0x7F);
57             result |= 0x80;
58         } else {
59             result = (short) value;
60         }
61         return result;
62     }
63
64     /**
65      * Extract an int from bytes at the given offset in the array.
66      *
67      * @param arr the array
68      * @param offset the offset in the array
69      */

70     private static int extractInt(byte[] arr, int offset) {
71         return ((arr[offset] & 0xFF) << 24) |
72                 ((arr[offset + 1] & 0xFF) << 16) |
73                 ((arr[offset + 2] & 0xFF) << 8) |
74                 (arr[offset + 3] & 0xFF);
75     }
76
77     private static final int PAD[] = {0, 3, 2, 1};
78
79     /**
80      * Scan the raw bytecodes of a method.
81      *
82      * @param instructionList the bytecodes
83      * @param callback the callback object
84      */

85     public void scan(byte[] instructionList, Callback callback) {
86
87         boolean wide = false;
88
89         for (int index = 0; index < instructionList.length;) {
90             short opcode = unsignedValueOf(instructionList[index]);
91             callback.handleInstruction(opcode, index);
92
93             if (DEBUG) System.out.println(index + ": " + OPCODE_NAMES[opcode]);
94
95             switch (opcode) {
96
97             // Single byte instructions.
98
case NOP:
99             case ACONST_NULL:
100             case ICONST_M1:
101             case ICONST_0:
102             case ICONST_1:
103             case ICONST_2:
104             case ICONST_3:
105             case ICONST_4:
106             case ICONST_5:
107             case LCONST_0:
108             case LCONST_1:
109             case FCONST_0:
110             case FCONST_1:
111             case FCONST_2:
112             case DCONST_0:
113             case DCONST_1:
114             case ILOAD_0:
115             case ILOAD_1:
116             case ILOAD_2:
117             case ILOAD_3:
118             case LLOAD_0:
119             case LLOAD_1:
120             case LLOAD_2:
121             case LLOAD_3:
122             case FLOAD_0:
123             case FLOAD_1:
124             case FLOAD_2:
125             case FLOAD_3:
126             case DLOAD_0:
127             case DLOAD_1:
128             case DLOAD_2:
129             case DLOAD_3:
130             case ALOAD_0:
131             case ALOAD_1:
132             case ALOAD_2:
133             case ALOAD_3:
134             case IALOAD:
135             case LALOAD:
136             case FALOAD:
137             case DALOAD:
138             case AALOAD:
139             case BALOAD:
140             case CALOAD:
141             case SALOAD:
142             case ISTORE_0:
143             case ISTORE_1:
144             case ISTORE_2:
145             case ISTORE_3:
146             case LSTORE_0:
147             case LSTORE_1:
148             case LSTORE_2:
149             case LSTORE_3:
150             case FSTORE_0:
151             case FSTORE_1:
152             case FSTORE_2:
153             case FSTORE_3:
154             case DSTORE_0:
155             case DSTORE_1:
156             case DSTORE_2:
157             case DSTORE_3:
158             case ASTORE_0:
159             case ASTORE_1:
160             case ASTORE_2:
161             case ASTORE_3:
162             case IASTORE:
163             case LASTORE:
164             case FASTORE:
165             case DASTORE:
166             case AASTORE:
167             case BASTORE:
168             case CASTORE:
169             case SASTORE:
170             case POP:
171             case POP2:
172             case DUP:
173             case DUP_X1:
174             case DUP_X2:
175             case DUP2:
176             case DUP2_X1:
177             case DUP2_X2:
178             case SWAP:
179             case IADD:
180             case LADD:
181             case FADD:
182             case DADD:
183             case ISUB:
184             case LSUB:
185             case FSUB:
186             case DSUB:
187             case IMUL:
188             case LMUL:
189             case FMUL:
190             case DMUL:
191             case IDIV:
192             case LDIV:
193             case FDIV:
194             case DDIV:
195             case IREM:
196             case LREM:
197             case FREM:
198             case DREM:
199             case INEG:
200             case LNEG:
201             case FNEG:
202             case DNEG:
203             case ISHL:
204             case LSHL:
205             case ISHR:
206             case LSHR:
207             case IUSHR:
208             case LUSHR:
209             case IAND:
210             case LAND:
211             case IOR:
212             case LOR:
213             case IXOR:
214             case LXOR:
215             case I2L:
216             case I2F:
217             case I2D:
218             case L2I:
219             case L2F:
220             case L2D:
221             case F2I:
222             case F2L:
223             case F2D:
224             case D2I:
225             case D2L:
226             case D2F:
227             case I2B:
228             case I2C:
229             case I2S:
230             case LCMP:
231             case FCMPL:
232             case FCMPG:
233             case DCMPL:
234             case DCMPG:
235             case IRETURN:
236             case LRETURN:
237             case FRETURN:
238             case DRETURN:
239             case ARETURN:
240             case RETURN:
241             case ARRAYLENGTH:
242             case ATHROW:
243             case MONITORENTER:
244             case MONITOREXIT:
245                 ++index;
246                 break;
247
248                 // Two byte instructions.
249
case BIPUSH:
250             case LDC:
251             case NEWARRAY:
252                 index += 2;
253                 break;
254
255                 // Instructions that can be used with the WIDE prefix.
256
case ILOAD:
257             case LLOAD:
258             case FLOAD:
259             case DLOAD:
260             case ALOAD:
261             case ISTORE:
262             case LSTORE:
263             case FSTORE:
264             case DSTORE:
265             case ASTORE:
266             case RET:
267                 if (wide) {
268                     // Skip opcode and two immediate bytes.
269
index += 3;
270                     wide = false;
271                 } else {
272                     // Skip opcode and one immediate byte.
273
index += 2;
274                 }
275                 break;
276
277                 // IINC is a special case for WIDE handling
278
case IINC:
279                 if (wide) {
280                     // Skip opcode, two byte index, and two byte immediate value.
281
index += 5;
282                     wide = false;
283                 } else {
284                     // Skip opcode, one byte index, and one byte immedate value.
285
index += 3;
286                 }
287                 break;
288
289                 // Three byte instructions.
290
case SIPUSH:
291             case LDC_W:
292             case LDC2_W:
293             case IFEQ:
294             case IFNE:
295             case IFLT:
296             case IFGE:
297             case IFGT:
298             case IFLE:
299             case IF_ICMPEQ:
300             case IF_ICMPNE:
301             case IF_ICMPLT:
302             case IF_ICMPGE:
303             case IF_ICMPGT:
304             case IF_ICMPLE:
305             case IF_ACMPEQ:
306             case IF_ACMPNE:
307             case GOTO:
308             case JSR:
309             case GETSTATIC:
310             case PUTSTATIC:
311             case GETFIELD:
312             case PUTFIELD:
313             case INVOKEVIRTUAL:
314             case INVOKESPECIAL:
315             case INVOKESTATIC:
316             case NEW:
317             case ANEWARRAY:
318             case CHECKCAST:
319             case INSTANCEOF:
320             case IFNULL:
321             case IFNONNULL:
322                 index += 3;
323                 break;
324
325                 // Four byte instructions.
326
case MULTIANEWARRAY:
327                 index += 4;
328                 break;
329
330                 // Five byte instructions.
331
case INVOKEINTERFACE:
332             case GOTO_W:
333             case JSR_W:
334                 index += 5;
335                 break;
336
337                 // TABLESWITCH - variable length.
338
case TABLESWITCH:
339                 {
340                     // Skip padding.
341
int offset = index + 1; // skip the opcode
342
offset += PAD[offset & 3];
343                     assert (offset & 3) == 0;
344
345                     // offset should now be posited at the default value
346

347                     // Extract min and max values.
348
int low = extractInt(instructionList, offset + 4);
349                     int high = extractInt(instructionList, offset + 8);
350                     int tableSize = (high - low) + 1;
351                     if (DEBUG) System.out.println("tableswitch: low=" + low + ", high=" + high + ", tableSize=" + tableSize);
352
353                     // Skip to next instruction.
354
index = offset + 12 + (tableSize * 4);
355                 }
356                 break;
357
358                 // LOOKUPSWITCH - variable length.
359
case LOOKUPSWITCH:
360                 {
361                     // Skip padding.
362
int offset = index + 1; // skip the opcode
363
offset += PAD[offset & 3];
364                     assert (offset & 3) == 0;
365
366                     // offset should now be posited at the default value
367

368                     // Extract number of value/offset pairs.
369
int numPairs = extractInt(instructionList, offset + 4);
370                     if (DEBUG) System.out.println("lookupswitch: numPairs=" + numPairs);
371
372                     // Skip to next instruction.
373
index = offset + 8 + (numPairs * 8);
374                 }
375                 break;
376
377                 // Wide prefix.
378
case WIDE:
379                 wide = true;
380                 ++index;
381                 break;
382
383             default:
384                 throw new IllegalArgumentException JavaDoc("Bad opcode " + opcode + " at offset " + index);
385             }
386
387             if (index < 0)
388                 throw new IllegalStateException JavaDoc("index=" + index + ", opcode=" + opcode);
389
390         }
391     }
392 }
393
394 // vim:ts=4
395
Popular Tags