1   // Copyright 2013 Bill Campbell, Swami Iyer and Bahar Akbal-Delibas
2   
3   package jminusminus;
4   
5   import java.util.ArrayList;
6   import java.util.Hashtable;
7   import java.util.Iterator;
8   import java.util.Set;
9   import java.util.TreeMap;
10  import java.util.Map.Entry;
11  import static jminusminus.CLConstants.*;
12  import static jminusminus.CLConstants.Category.*;
13  
14  /**
15   * Representation of a JVM instruction. It stores the opcode and mnenomic of an
16   * instruction, its operand count (DYNAMIC if the instruction has variable
17   * number operands), pc (location counter), stack units (words produced - words
18   * consumed from the operand stack), and local variable index (IRRELEVANT if the
19   * instruction does not operate on local variables).
20   */
21  
22  abstract class CLInstruction {
23  
24      /** Opcode for this instruction. */
25      protected int opcode;
26  
27      /** Mnemonic for this instruction. */
28      protected String mnemonic;
29  
30      /**
31       * Number of operands for this instruction; determined statically for all
32       * instructions except TABLESWITCH and LOOKUPSWITCH.
33       */
34      protected int operandCount;
35  
36      /**
37       * Location counter; index of this instruction within the code array of a
38       * method.
39       */
40      protected int pc;
41  
42      /**
43       * Stack units; words produced - words consumed from the operand stack by
44       * this instruction.
45       */
46      protected int stackUnits;
47  
48      /**
49       * Index of the local variable that this instruction refers to; applies only
50       * to instructions that operate on local variables.
51       */
52      protected int localVariableIndex;
53  
54      /**
55       * For each JVM instruction, this array stores its opcode, mnemonic, number
56       * of operands (DYNAMIC for instructions with variable attribute count),
57       * local variable index (IRRELEVANT where not applicable), stack units, and
58       * instruction category. For example, for IMUL, these parameters are IMUL,
59       * "imul", 0, IRRELEVANT, -1, ARITHMETIC1.
60       */
61      public static final CLInsInfo[] instructionInfo = {
62              new CLInsInfo(NOP, "nop", 0, IRRELEVANT, 0, MISC),
63              new CLInsInfo(ACONST_NULL, "aconst_null", 0, IRRELEVANT, 1,
64                      LOAD_STORE1),
65              new CLInsInfo(ICONST_M1, "iconst_m1", 0, IRRELEVANT, 1, LOAD_STORE1),
66              new CLInsInfo(ICONST_0, "iconst_0", 0, IRRELEVANT, 1, LOAD_STORE1),
67              new CLInsInfo(ICONST_1, "iconst_1", 0, IRRELEVANT, 1, LOAD_STORE1),
68              new CLInsInfo(ICONST_2, "iconst_2", 0, IRRELEVANT, 1, LOAD_STORE1),
69              new CLInsInfo(ICONST_3, "iconst_3", 0, IRRELEVANT, 1, LOAD_STORE1),
70              new CLInsInfo(ICONST_4, "iconst_4", 0, IRRELEVANT, 1, LOAD_STORE1),
71              new CLInsInfo(ICONST_5, "iconst_5", 0, IRRELEVANT, 1, LOAD_STORE1),
72              new CLInsInfo(LCONST_0, "lconst_0", 0, IRRELEVANT, 2, LOAD_STORE1),
73              new CLInsInfo(LCONST_1, "lconst_1", 0, IRRELEVANT, 2, LOAD_STORE1),
74              new CLInsInfo(FCONST_0, "fconst_0", 0, IRRELEVANT, 1, LOAD_STORE1),
75              new CLInsInfo(FCONST_1, "fconst_1", 0, IRRELEVANT, 1, LOAD_STORE1),
76              new CLInsInfo(FCONST_2, "fconst_2", 0, IRRELEVANT, 1, LOAD_STORE1),
77              new CLInsInfo(DCONST_0, "dconst_0", 0, IRRELEVANT, 2, LOAD_STORE1),
78              new CLInsInfo(DCONST_1, "dconst_1", 0, IRRELEVANT, 2, LOAD_STORE1),
79              new CLInsInfo(BIPUSH, "bipush", 1, IRRELEVANT, 1, LOAD_STORE3),
80              new CLInsInfo(SIPUSH, "sipush", 2, IRRELEVANT, 1, LOAD_STORE3),
81              new CLInsInfo(LDC, "ldc", 1, IRRELEVANT, 1, LOAD_STORE4),
82              new CLInsInfo(LDC_W, "ldc_w", 2, IRRELEVANT, 1, LOAD_STORE4),
83              new CLInsInfo(LDC2_W, "ldc2_w", 2, IRRELEVANT, 2, LOAD_STORE4),
84              new CLInsInfo(ILOAD, "iload", 1, DYNAMIC, 1, LOAD_STORE2),
85              new CLInsInfo(LLOAD, "lload", 1, DYNAMIC, 2, LOAD_STORE2),
86              new CLInsInfo(FLOAD, "fload", 1, DYNAMIC, 1, LOAD_STORE2),
87              new CLInsInfo(DLOAD, "dload", 1, DYNAMIC, 2, LOAD_STORE2),
88              new CLInsInfo(ALOAD, "aload", 1, DYNAMIC, 1, LOAD_STORE2),
89              new CLInsInfo(ILOAD_0, "iload_0", 0, 0, 1, LOAD_STORE1),
90              new CLInsInfo(ILOAD_1, "iload_1", 0, 1, 1, LOAD_STORE1),
91              new CLInsInfo(ILOAD_2, "iload_2", 0, 2, 1, LOAD_STORE1),
92              new CLInsInfo(ILOAD_3, "iload_3", 0, 3, 1, LOAD_STORE1),
93              new CLInsInfo(LLOAD_0, "lload_0", 0, 0, 2, LOAD_STORE1),
94              new CLInsInfo(LLOAD_1, "lload_1", 0, 1, 2, LOAD_STORE1),
95              new CLInsInfo(LLOAD_2, "lload_2", 0, 2, 2, LOAD_STORE1),
96              new CLInsInfo(LLOAD_3, "lload_3", 0, 3, 2, LOAD_STORE1),
97              new CLInsInfo(FLOAD_0, "fload_0", 0, 0, 1, LOAD_STORE1),
98              new CLInsInfo(FLOAD_1, "fload_1", 0, 1, 1, LOAD_STORE1),
99              new CLInsInfo(FLOAD_2, "fload_2", 0, 2, 1, LOAD_STORE1),
100             new CLInsInfo(FLOAD_3, "fload_3", 0, 3, 1, LOAD_STORE1),
101             new CLInsInfo(DLOAD_0, "dload_0", 0, 0, 2, LOAD_STORE1),
102             new CLInsInfo(DLOAD_1, "dload_1", 0, 1, 2, LOAD_STORE1),
103             new CLInsInfo(DLOAD_2, "dload_2", 0, 2, 2, LOAD_STORE1),
104             new CLInsInfo(DLOAD_3, "dload_3", 0, 3, 2, LOAD_STORE1),
105             new CLInsInfo(ALOAD_0, "aload_0", 0, 0, 1, LOAD_STORE1),
106             new CLInsInfo(ALOAD_1, "aload_1", 0, 1, 1, LOAD_STORE1),
107             new CLInsInfo(ALOAD_2, "aload_2", 0, 2, 1, LOAD_STORE1),
108             new CLInsInfo(ALOAD_3, "aload_3", 0, 3, 1, LOAD_STORE1),
109             new CLInsInfo(IALOAD, "iaload", 0, IRRELEVANT, -1, ARRAY2),
110             new CLInsInfo(LALOAD, "laload", 0, IRRELEVANT, 0, ARRAY2),
111             new CLInsInfo(FALOAD, "faload", 0, IRRELEVANT, -1, ARRAY2),
112             new CLInsInfo(DALOAD, "daload", 0, IRRELEVANT, 0, ARRAY2),
113             new CLInsInfo(AALOAD, "aaload", 0, IRRELEVANT, -1, ARRAY2),
114             new CLInsInfo(BALOAD, "baload", 0, IRRELEVANT, -1, ARRAY2),
115             new CLInsInfo(CALOAD, "caload", 0, IRRELEVANT, -1, ARRAY2),
116             new CLInsInfo(SALOAD, "saload", 0, IRRELEVANT, -1, ARRAY2),
117             new CLInsInfo(ISTORE, "istore", 1, DYNAMIC, -1, LOAD_STORE2),
118             new CLInsInfo(LSTORE, "lstore", 1, DYNAMIC, -2, LOAD_STORE2),
119             new CLInsInfo(FSTORE, "fstore", 1, DYNAMIC, -1, LOAD_STORE2),
120             new CLInsInfo(DSTORE, "dstore", 1, DYNAMIC, -2, LOAD_STORE2),
121             new CLInsInfo(ASTORE, "astore", 1, DYNAMIC, -1, LOAD_STORE2),
122             new CLInsInfo(ISTORE_0, "istore_0", 0, 0, -1, LOAD_STORE1),
123             new CLInsInfo(ISTORE_1, "istore_1", 0, 1, -1, LOAD_STORE1),
124             new CLInsInfo(ISTORE_2, "istore_2", 0, 2, -1, LOAD_STORE1),
125             new CLInsInfo(ISTORE_3, "istore_3", 0, 3, -1, LOAD_STORE1),
126             new CLInsInfo(LSTORE_0, "lstore_0", 0, 0, -2, LOAD_STORE1),
127             new CLInsInfo(LSTORE_1, "lstore_1", 0, 1, -2, LOAD_STORE1),
128             new CLInsInfo(LSTORE_2, "lstore_2", 0, 2, -2, LOAD_STORE1),
129             new CLInsInfo(LSTORE_3, "lstore_3", 0, 3, -2, LOAD_STORE1),
130             new CLInsInfo(FSTORE_0, "fstore_0", 0, 0, -1, LOAD_STORE1),
131             new CLInsInfo(FSTORE_1, "fstore_1", 0, 1, -1, LOAD_STORE1),
132             new CLInsInfo(FSTORE_2, "fstore_2", 0, 2, -1, LOAD_STORE1),
133             new CLInsInfo(FSTORE_3, "fstore_3", 0, 3, -1, LOAD_STORE1),
134             new CLInsInfo(DSTORE_0, "dstore_0", 0, 0, -2, LOAD_STORE1),
135             new CLInsInfo(DSTORE_1, "dstore_1", 0, 1, -2, LOAD_STORE1),
136             new CLInsInfo(DSTORE_2, "dstore_2", 0, 2, -2, LOAD_STORE1),
137             new CLInsInfo(DSTORE_3, "dstore_3", 0, 3, -2, LOAD_STORE1),
138             new CLInsInfo(ASTORE_0, "astore_0", 0, 0, -1, LOAD_STORE1),
139             new CLInsInfo(ASTORE_1, "astore_1", 0, 1, -1, LOAD_STORE1),
140             new CLInsInfo(ASTORE_2, "astore_2", 0, 2, -1, LOAD_STORE1),
141             new CLInsInfo(ASTORE_3, "astore_3", 0, 3, -1, LOAD_STORE1),
142             new CLInsInfo(IASTORE, "iastore", 0, IRRELEVANT, -3, ARRAY2),
143             new CLInsInfo(LASTORE, "lastore", 0, IRRELEVANT, -4, ARRAY2),
144             new CLInsInfo(FASTORE, "fastore", 0, IRRELEVANT, -3, ARRAY2),
145             new CLInsInfo(DASTORE, "dastore", 0, IRRELEVANT, -4, ARRAY2),
146             new CLInsInfo(AASTORE, "aastore", 0, IRRELEVANT, -3, ARRAY2),
147             new CLInsInfo(BASTORE, "bastore", 0, IRRELEVANT, -3, ARRAY2),
148             new CLInsInfo(CASTORE, "castore", 0, IRRELEVANT, -3, ARRAY2),
149             new CLInsInfo(SASTORE, "sastore", 0, IRRELEVANT, -3, ARRAY2),
150             new CLInsInfo(POP, "pop", 0, IRRELEVANT, -1, STACK),
151             new CLInsInfo(POP2, "pop2", 0, IRRELEVANT, -2, STACK),
152             new CLInsInfo(DUP, "dup", 0, IRRELEVANT, 1, STACK),
153             new CLInsInfo(DUP_X1, "dup_x1", 0, IRRELEVANT, 1, STACK),
154             new CLInsInfo(DUP_X2, "dup_x2", 0, IRRELEVANT, 1, STACK),
155             new CLInsInfo(DUP2, "dup2", 0, IRRELEVANT, 2, STACK),
156             new CLInsInfo(DUP2_X1, "dup2_x1", 0, IRRELEVANT, 2, STACK),
157             new CLInsInfo(DUP2_X2, "dup2_x2", 0, IRRELEVANT, 2, STACK),
158             new CLInsInfo(SWAP, "swap", 0, IRRELEVANT, 0, STACK),
159             new CLInsInfo(IADD, "iadd", 0, IRRELEVANT, -1, ARITHMETIC1),
160             new CLInsInfo(LADD, "ladd", 0, IRRELEVANT, -2, ARITHMETIC1),
161             new CLInsInfo(FADD, "fadd", 0, IRRELEVANT, -1, ARITHMETIC1),
162             new CLInsInfo(DADD, "dadd", 0, IRRELEVANT, -2, ARITHMETIC1),
163             new CLInsInfo(ISUB, "isub", 0, IRRELEVANT, -1, ARITHMETIC1),
164             new CLInsInfo(LSUB, "lsub", 0, IRRELEVANT, -2, ARITHMETIC1),
165             new CLInsInfo(FSUB, "fsub", 0, IRRELEVANT, -1, ARITHMETIC1),
166             new CLInsInfo(DSUB, "dsub", 0, IRRELEVANT, -2, ARITHMETIC1),
167             new CLInsInfo(IMUL, "imul", 0, IRRELEVANT, -1, ARITHMETIC1),
168             new CLInsInfo(LMUL, "lmul", 0, IRRELEVANT, -2, ARITHMETIC1),
169             new CLInsInfo(FMUL, "fmul", 0, IRRELEVANT, -1, ARITHMETIC1),
170             new CLInsInfo(DMUL, "dmul", 0, IRRELEVANT, -2, ARITHMETIC1),
171             new CLInsInfo(IDIV, "idiv", 0, IRRELEVANT, -1, ARITHMETIC1),
172             new CLInsInfo(LDIV, "ldiv", 0, IRRELEVANT, -2, ARITHMETIC1),
173             new CLInsInfo(FDIV, "fdiv", 0, IRRELEVANT, -1, ARITHMETIC1),
174             new CLInsInfo(DDIV, "ddiv", 0, IRRELEVANT, -2, ARITHMETIC1),
175             new CLInsInfo(IREM, "irem", 0, IRRELEVANT, -1, ARITHMETIC1),
176             new CLInsInfo(LREM, "lrem", 0, IRRELEVANT, -2, ARITHMETIC1),
177             new CLInsInfo(FREM, "frem", 0, IRRELEVANT, -1, ARITHMETIC1),
178             new CLInsInfo(DREM, "drem", 0, IRRELEVANT, -2, ARITHMETIC1),
179             new CLInsInfo(INEG, "ineg", 0, IRRELEVANT, 0, ARITHMETIC1),
180             new CLInsInfo(LNEG, "lneg", 0, IRRELEVANT, 0, ARITHMETIC1),
181             new CLInsInfo(FNEG, "fneg", 0, IRRELEVANT, 0, ARITHMETIC1),
182             new CLInsInfo(DNEG, "dneg", 0, IRRELEVANT, 0, ARITHMETIC1),
183             new CLInsInfo(ISHL, "ishl", 0, IRRELEVANT, -1, BIT),
184             new CLInsInfo(LSHL, "lshl", 0, IRRELEVANT, -2, BIT),
185             new CLInsInfo(ISHR, "ishr", 0, IRRELEVANT, -1, BIT),
186             new CLInsInfo(LSHR, "lshr", 0, IRRELEVANT, -2, BIT),
187             new CLInsInfo(IUSHR, "iushr", 0, IRRELEVANT, -1, BIT),
188             new CLInsInfo(LUSHR, "lushr", 0, IRRELEVANT, -2, BIT),
189             new CLInsInfo(IAND, "iand", 0, IRRELEVANT, -1, BIT),
190             new CLInsInfo(LAND, "land", 0, IRRELEVANT, -2, BIT),
191             new CLInsInfo(IOR, "ior", 0, IRRELEVANT, -1, BIT),
192             new CLInsInfo(LOR, "lor", 0, IRRELEVANT, -2, BIT),
193             new CLInsInfo(IXOR, "ixor", 0, IRRELEVANT, -1, BIT),
194             new CLInsInfo(LXOR, "lxor", 0, IRRELEVANT, -2, BIT),
195             new CLInsInfo(IINC, "iinc", 2, DYNAMIC, 0, ARITHMETIC2),
196             new CLInsInfo(I2L, "i2l", 0, IRRELEVANT, 1, CONVERSION),
197             new CLInsInfo(I2F, "i2f", 0, IRRELEVANT, 0, CONVERSION),
198             new CLInsInfo(I2D, "i2d", 0, IRRELEVANT, 1, CONVERSION),
199             new CLInsInfo(L2I, "l2i", 0, IRRELEVANT, -1, CONVERSION),
200             new CLInsInfo(L2F, "l2f", 0, IRRELEVANT, -1, CONVERSION),
201             new CLInsInfo(L2D, "l2d", 0, IRRELEVANT, 0, CONVERSION),
202             new CLInsInfo(F2I, "f2i", 0, IRRELEVANT, 0, CONVERSION),
203             new CLInsInfo(F2L, "f2l", 0, IRRELEVANT, 1, CONVERSION),
204             new CLInsInfo(F2D, "f2d", 0, IRRELEVANT, 1, CONVERSION),
205             new CLInsInfo(D2I, "d2i", 0, IRRELEVANT, -1, CONVERSION),
206             new CLInsInfo(D2L, "d2l", 0, IRRELEVANT, 0, CONVERSION),
207             new CLInsInfo(D2F, "d2f", 0, IRRELEVANT, -1, CONVERSION),
208             new CLInsInfo(I2B, "i2b", 0, IRRELEVANT, 0, CONVERSION),
209             new CLInsInfo(I2C, "i2c", 0, IRRELEVANT, 0, CONVERSION),
210             new CLInsInfo(I2S, "i2s", 0, IRRELEVANT, 0, CONVERSION),
211             new CLInsInfo(LCMP, "lcmp", 0, IRRELEVANT, -3, COMPARISON),
212             new CLInsInfo(FCMPL, "fcmpl", 0, IRRELEVANT, -1, COMPARISON),
213             new CLInsInfo(FCMPG, "fcmpg", 0, IRRELEVANT, -1, COMPARISON),
214             new CLInsInfo(DCMPL, "dcmpl", 0, IRRELEVANT, -3, COMPARISON),
215             new CLInsInfo(DCMPG, "dcmpg", 0, IRRELEVANT, -3, COMPARISON),
216             new CLInsInfo(IFEQ, "ifeq", 2, IRRELEVANT, -1, FLOW_CONTROL1),
217             new CLInsInfo(IFNE, "ifne", 2, IRRELEVANT, -1, FLOW_CONTROL1),
218             new CLInsInfo(IFLT, "iflt", 2, IRRELEVANT, -1, FLOW_CONTROL1),
219             new CLInsInfo(IFGE, "ifge", 2, IRRELEVANT, -1, FLOW_CONTROL1),
220             new CLInsInfo(IFGT, "ifgt", 2, IRRELEVANT, -1, FLOW_CONTROL1),
221             new CLInsInfo(IFLE, "ifle", 2, IRRELEVANT, -1, FLOW_CONTROL1),
222             new CLInsInfo(IF_ICMPEQ, "if_icmpeq", 2, IRRELEVANT, -2,
223                     FLOW_CONTROL1),
224             new CLInsInfo(IF_ICMPNE, "if_icmpne", 2, IRRELEVANT, -2,
225                     FLOW_CONTROL1),
226             new CLInsInfo(IF_ICMPLT, "if_icmplt", 2, IRRELEVANT, -2,
227                     FLOW_CONTROL1),
228             new CLInsInfo(IF_ICMPGE, "if_icmpge", 2, IRRELEVANT, -2,
229                     FLOW_CONTROL1),
230             new CLInsInfo(IF_ICMPGT, "if_icmpgt", 2, IRRELEVANT, -2,
231                     FLOW_CONTROL1),
232             new CLInsInfo(IF_ICMPLE, "if_icmple", 2, IRRELEVANT, -2,
233                     FLOW_CONTROL1),
234             new CLInsInfo(IF_ACMPEQ, "if_acmpeq", 2, IRRELEVANT, -2,
235                     FLOW_CONTROL1),
236             new CLInsInfo(IF_ACMPNE, "if_acmpne", 2, IRRELEVANT, -2,
237                     FLOW_CONTROL1),
238             new CLInsInfo(GOTO, "goto", 2, IRRELEVANT, 0, FLOW_CONTROL1),
239             new CLInsInfo(JSR, "jsr", 2, IRRELEVANT, 1, FLOW_CONTROL1),
240             new CLInsInfo(RET, "ret", 1, IRRELEVANT, 0, FLOW_CONTROL2),
241             new CLInsInfo(TABLESWITCH, "tableswitch", DYNAMIC, IRRELEVANT, -1,
242                     FLOW_CONTROL3),
243             new CLInsInfo(LOOKUPSWITCH, "lookupswitch", DYNAMIC, IRRELEVANT,
244                     -1, FLOW_CONTROL4),
245             new CLInsInfo(IRETURN, "ireturn", 0, IRRELEVANT, EMPTY_STACK,
246                     METHOD2),
247             new CLInsInfo(LRETURN, "lreturn", 0, IRRELEVANT, EMPTY_STACK,
248                     METHOD2),
249             new CLInsInfo(FRETURN, "freturn", 0, IRRELEVANT, EMPTY_STACK,
250                     METHOD2),
251             new CLInsInfo(DRETURN, "dreturn", 0, IRRELEVANT, EMPTY_STACK,
252                     METHOD2),
253             new CLInsInfo(ARETURN, "areturn", 0, IRRELEVANT, EMPTY_STACK,
254                     METHOD2),
255             new CLInsInfo(RETURN, "return", 0, IRRELEVANT, EMPTY_STACK, METHOD2),
256             new CLInsInfo(GETSTATIC, "getstatic", 2, IRRELEVANT, DYNAMIC, FIELD),
257             new CLInsInfo(PUTSTATIC, "putstatic", 2, IRRELEVANT, DYNAMIC, FIELD),
258             new CLInsInfo(GETFIELD, "getfield", 2, IRRELEVANT, DYNAMIC, FIELD),
259             new CLInsInfo(PUTFIELD, "putfield", 2, IRRELEVANT, DYNAMIC, FIELD),
260             new CLInsInfo(INVOKEVIRTUAL, "invokevirtual", 2, IRRELEVANT,
261                     DYNAMIC, METHOD1),
262             new CLInsInfo(INVOKESPECIAL, "invokespecial", 2, IRRELEVANT,
263                     DYNAMIC, METHOD1),
264             new CLInsInfo(INVOKESTATIC, "invokestatic", 2, IRRELEVANT, DYNAMIC,
265                     METHOD1),
266             new CLInsInfo(INVOKEINTERFACE, "invokeinterface", 4, IRRELEVANT,
267                     DYNAMIC, METHOD1),
268             new CLInsInfo(INVOKEDYNAMIC, "invokedynamic", 2, IRRELEVANT,
269                     DYNAMIC, METHOD1),
270             new CLInsInfo(NEW, "new", 2, IRRELEVANT, 1, OBJECT),
271             new CLInsInfo(NEWARRAY, "newarray", 1, IRRELEVANT, 0, ARRAY1),
272             new CLInsInfo(ANEWARRAY, "anewarray", 2, IRRELEVANT, 0, ARRAY1),
273             new CLInsInfo(ARRAYLENGTH, "arraylength", 0, IRRELEVANT, 0, ARRAY2),
274             new CLInsInfo(ATHROW, "athrow", 0, IRRELEVANT, UNIT_SIZE_STACK,
275                     MISC),
276             new CLInsInfo(CHECKCAST, "checkcast", 2, IRRELEVANT, 0, OBJECT),
277             new CLInsInfo(INSTANCEOF, "instanceof", 2, IRRELEVANT, 0, OBJECT),
278             new CLInsInfo(MONITORENTER, "monitorenter", 0, IRRELEVANT, -1, MISC),
279             new CLInsInfo(MONITOREXIT, "monitorexit", 0, IRRELEVANT, -1, MISC),
280             new CLInsInfo(WIDE, "wide", 3, IRRELEVANT, 0, LOAD_STORE1),
281             new CLInsInfo(MULTIANEWARRAY, "multianewarray", 3, IRRELEVANT, 0,
282                     ARRAY3),
283             new CLInsInfo(IFNULL, "ifnull", 2, IRRELEVANT, -1, FLOW_CONTROL1),
284             new CLInsInfo(IFNONNULL, "ifnonnull", 2, IRRELEVANT, -1,
285                     FLOW_CONTROL1),
286             new CLInsInfo(GOTO_W, "goto_w", 4, IRRELEVANT, 0, FLOW_CONTROL1),
287             new CLInsInfo(JSR_W, "jsr_w", 4, IRRELEVANT, 1, FLOW_CONTROL1) };
288 
289     /**
290      * Return true if the opcode is valid; false otherwise.
291      * 
292      * @param opcode
293      *            instruction opcode.
294      * @return true or false.
295      */
296 
297     public static boolean isValid(int opcode) {
298         return NOP <= opcode && opcode <= JSR_W;
299     }
300 
301     /**
302      * Return the opcode for this instruction.
303      * 
304      * @return the opcode.
305      */
306 
307     public int opcode() {
308         return opcode;
309     }
310 
311     /**
312      * Return the mnemonic for this instruction.
313      * 
314      * @return the mnemonic.
315      */
316 
317     public String mnemonic() {
318         return mnemonic;
319     }
320 
321     /**
322      * Return the number of operands for this instruction.
323      * 
324      * @return number of operands.
325      */
326 
327     public int operandCount() {
328         return operandCount;
329     }
330 
331     /**
332      * Return the pc for this instruction.
333      * 
334      * @return the pc.
335      */
336 
337     public int pc() {
338         return pc;
339     }
340 
341     /**
342      * Return the stack units for this instruction.
343      * 
344      * @return the stack units.
345      */
346 
347     public int stackUnits() {
348         return stackUnits;
349     }
350 
351     /**
352      * Return the local variable index for this instruction.
353      * 
354      * @return the local variable index.
355      */
356 
357     public int localVariableIndex() {
358         return localVariableIndex;
359     }
360 
361     /**
362      * Return the bytecode for this instruction.
363      * 
364      * @return bytecode.
365      */
366 
367     public abstract ArrayList<Integer> toBytes();
368 
369     /**
370      * Return the byte from i at position byteNum.
371      * 
372      * @param i
373      *            number whose individual byte is required.
374      * @param byteNum
375      *            the byte to return; 1 (lower) - 4 (higher) instructions.
376      * @return the byte at the specified position.
377      */
378 
379     protected int byteAt(int i, int byteNum) {
380         int j = 0, mask = 0xFF;
381         switch (byteNum) {
382         case 1: // lower order
383             j = i & mask;
384             break;
385         case 2:
386             j = (i >> 8) & mask;
387             break;
388         case 3:
389             j = (i >> 16) & mask;
390             break;
391         case 4: // higher order
392             j = (i >> 24) & mask;
393             break;
394         }
395         return j;
396     }
397 
398 }
399 
400 /**
401  * Representation for OBJECT instructions.
402  */
403 
404 class CLObjectInstruction extends CLInstruction {
405 
406     /**
407      * Index into the constant pool, the item at which identifies the object
408      * type.
409      */
410     private int index;
411 
412     /**
413      * Construct a CLObjectInstruction object.
414      * 
415      * @param opcode
416      *            the opcode for this instruction.
417      * @param pc
418      *            index of this instruction within the code array of a method.
419      * @param index
420      *            index into the constant pool, the item at which identifies the
421      *            object.
422      */
423 
424     public CLObjectInstruction(int opcode, int pc, int index) {
425         super.opcode = opcode;
426         super.pc = pc;
427         mnemonic = instructionInfo[opcode].mnemonic;
428         operandCount = instructionInfo[opcode].operandCount;
429         stackUnits = instructionInfo[opcode].stackUnits;
430         localVariableIndex = instructionInfo[opcode].localVariableIndex;
431         this.index = index;
432     }
433 
434     /**
435      * @inheritDoc
436      */
437 
438     public ArrayList<Integer> toBytes() {
439         ArrayList<Integer> bytes = new ArrayList<Integer>();
440         bytes.add(opcode);
441         bytes.add(byteAt(index, 2));
442         bytes.add(byteAt(index, 1));
443         return bytes;
444     }
445 
446 }
447 
448 /**
449  * Representation for FIELD instructions.
450  */
451 
452 class CLFieldInstruction extends CLInstruction {
453 
454     /**
455      * Index into the constant pool, the item at which contains the name and
456      * descriptor of the field.
457      */
458     private int index;
459 
460     /**
461      * Construct a CLFieldInstruction object.
462      * 
463      * @param opcode
464      *            the opcode for this instruction.
465      * @param pc
466      *            index of this instruction within the code array of a method.
467      * @param index
468      *            index into the constant pool, the item at which contains the
469      *            name and descriptor of the field.
470      * @param stackUnits
471      *            words produced - words consumed from the operand stack by this
472      *            instruction.
473      */
474 
475     public CLFieldInstruction(int opcode, int pc, int index, int stackUnits) {
476         super.opcode = opcode;
477         super.pc = pc;
478         mnemonic = instructionInfo[opcode].mnemonic;
479         operandCount = instructionInfo[opcode].operandCount;
480         super.stackUnits = stackUnits;
481         localVariableIndex = instructionInfo[opcode].localVariableIndex;
482         this.index = index;
483     }
484 
485     /**
486      * @inheritDoc
487      */
488 
489     public ArrayList<Integer> toBytes() {
490         ArrayList<Integer> bytes = new ArrayList<Integer>();
491         bytes.add(opcode);
492         bytes.add(byteAt(index, 2));
493         bytes.add(byteAt(index, 1));
494         return bytes;
495     }
496 
497 }
498 
499 /**
500  * Representation for METHOD1 and METHOD2 instructions.
501  */
502 
503 class CLMethodInstruction extends CLInstruction {
504 
505     /**
506      * Index into the constant pool, the item at which contains the name and
507      * descriptor of the method.
508      */
509     private int index;
510 
511     /**
512      * Number of arguments in case of INVOKEINTERFACE instruction.
513      */
514     private int nArgs;
515 
516     /**
517      * Construct a CLMethodInstruction object for METHOD1 instructions.
518      * 
519      * @param opcode
520      *            the opcode for this instruction.
521      * @param pc
522      *            index of this instruction within the code array of a method.
523      * @param index
524      *            index into the constant pool, the item at which contains the
525      *            name and descriptor of the method.
526      * @param stackUnits
527      *            words produced - words consumed from the operand stack by this
528      *            instruction.
529      */
530 
531     public CLMethodInstruction(int opcode, int pc, int index, int stackUnits) {
532         super.opcode = opcode;
533         super.pc = pc;
534         mnemonic = instructionInfo[opcode].mnemonic;
535         operandCount = instructionInfo[opcode].operandCount;
536         super.stackUnits = stackUnits;
537         localVariableIndex = instructionInfo[opcode].localVariableIndex;
538         this.index = index;
539     }
540 
541     /**
542      * Construct a CLMethodInstruction object for METHOD2 instructions.
543      * 
544      * @param opcode
545      *            the opcode for this instruction.
546      * @param pc
547      *            index of this instruction within the code array of a method.
548      */
549 
550     public CLMethodInstruction(int opcode, int pc) {
551         super.opcode = opcode;
552         super.pc = pc;
553         mnemonic = instructionInfo[opcode].mnemonic;
554         operandCount = instructionInfo[opcode].operandCount;
555         stackUnits = instructionInfo[opcode].stackUnits;
556         localVariableIndex = instructionInfo[opcode].localVariableIndex;
557     }
558 
559     /**
560      * Set the number of arguments for the method for INVOKEINTERFACE
561      * instruction.
562      * 
563      * @param nArgs
564      *            number of arguments for the method.
565      */
566 
567     public void setArgumentCount(int nArgs) {
568         this.nArgs = nArgs;
569     }
570 
571     /**
572      * @inheritDoc
573      */
574 
575     public ArrayList<Integer> toBytes() {
576         ArrayList<Integer> bytes = new ArrayList<Integer>();
577         bytes.add(opcode);
578         if (instructionInfo[opcode].category == METHOD1) {
579             bytes.add(byteAt(index, 2));
580             bytes.add(byteAt(index, 1));
581 
582             // INVOKEINTERFACE expects the number of arguments of
583             // the method as the third operand and a fourth
584             // argument which must always be 0.
585             if (opcode == INVOKEINTERFACE) {
586                 bytes.add(byteAt(nArgs, 1));
587                 bytes.add(0);
588             }
589         }
590         return bytes;
591     }
592 
593 }
594 
595 /**
596  * Representation for ARRAY1, ARRAY2 and ARRAY3 instructions.
597  */
598 
599 class CLArrayInstruction extends CLInstruction {
600 
601     /**
602      * A number identifying the type of primitive array, or an index into the
603      * constant pool, the item at which specifies the reference type of the
604      * array.
605      */
606     private int type;
607 
608     /** Number of dimensions in case of a multi-dimensional array. */
609     private int dim;
610 
611     /**
612      * Construct a CLArrayInstruction object for ARRAY1 instructions.
613      * 
614      * @param opcode
615      *            the opcode for this instruction.
616      * @param pc
617      *            index of this instruction within the code array of a method.
618      * @param type
619      *            number identifying the type.
620      */
621 
622     public CLArrayInstruction(int opcode, int pc, int type) {
623         super.opcode = opcode;
624         super.pc = pc;
625         mnemonic = instructionInfo[opcode].mnemonic;
626         operandCount = instructionInfo[opcode].operandCount;
627         stackUnits = instructionInfo[opcode].stackUnits;
628         localVariableIndex = instructionInfo[opcode].localVariableIndex;
629         this.type = type;
630     }
631 
632     /**
633      * Construct a CLArrayInstruction object for ARRAY2 instructions.
634      * 
635      * @param opcode
636      *            the opcode for this instruction.
637      * @param pc
638      *            index of this instruction within the code array of a method.
639      * @param type
640      *            number identifying the type.
641      * @param dim
642      *            number of dimensions.
643      */
644 
645     public CLArrayInstruction(int opcode, int pc, int type, int dim) {
646         super.opcode = opcode;
647         super.pc = pc;
648         mnemonic = instructionInfo[opcode].mnemonic;
649         operandCount = instructionInfo[opcode].operandCount;
650         stackUnits = instructionInfo[opcode].stackUnits;
651         localVariableIndex = instructionInfo[opcode].localVariableIndex;
652         this.type = type;
653         this.dim = dim;
654     }
655 
656     /**
657      * Construct a CLArrayInstruction object for ARRAY3 instructions.
658      * 
659      * @param opcode
660      *            the opcode for this instruction.
661      * @param pc
662      *            index of this instruction within the code array of a method.
663      */
664 
665     public CLArrayInstruction(int opcode, int pc) {
666         super.opcode = opcode;
667         super.pc = pc;
668         mnemonic = instructionInfo[opcode].mnemonic;
669         operandCount = instructionInfo[opcode].operandCount;
670         stackUnits = instructionInfo[opcode].stackUnits;
671         localVariableIndex = instructionInfo[opcode].localVariableIndex;
672     }
673 
674     /**
675      * @inheritDoc
676      */
677 
678     public ArrayList<Integer> toBytes() {
679         ArrayList<Integer> bytes = new ArrayList<Integer>();
680         bytes.add(opcode);
681         switch (opcode) {
682         case NEWARRAY:
683             bytes.add(byteAt(type, 1));
684             break;
685         case ANEWARRAY:
686             bytes.add(byteAt(type, 2));
687             bytes.add(byteAt(type, 1));
688             break;
689         case MULTIANEWARRAY:
690             bytes.add(byteAt(type, 2));
691             bytes.add(byteAt(type, 1));
692             bytes.add(byteAt(dim, 1));
693             break;
694         }
695         return bytes;
696     }
697 
698 }
699 
700 /**
701  * Representation for ARITHMETIC1 and ARITHMETIC2 instructions.
702  */
703 
704 class CLArithmeticInstruction extends CLInstruction {
705 
706     /**
707      * Whether this instruction is preceeded by a WIDE instruction; applies only
708      * to IINC.
709      */
710     private boolean isWidened;
711 
712     /** Increment value for IINC instruction. */
713     private int constVal;
714 
715     /**
716      * Construct a CLArithmeticInstruction object for ARITHMETIC1 instructions.
717      * 
718      * @param opcode
719      *            the opcode for this instruction.
720      * @param pc
721      *            index of this instruction within the code array of a method.
722      */
723 
724     public CLArithmeticInstruction(int opcode, int pc) {
725         super.opcode = opcode;
726         super.pc = pc;
727         mnemonic = instructionInfo[opcode].mnemonic;
728         operandCount = instructionInfo[opcode].operandCount;
729         stackUnits = instructionInfo[opcode].stackUnits;
730         localVariableIndex = instructionInfo[opcode].localVariableIndex;
731     }
732 
733     /**
734      * Construct a CLArithmeticInstruction object for IINC instruction.
735      * 
736      * @param opcode
737      *            the opcode for this instruction.
738      * @param pc
739      *            index of this instruction within the code array of a method.
740      * @param localVariableIndex
741      *            index of the local variable to increment.
742      * @param constVal
743      *            increment value.
744      * @param isWidened
745      *            whether this instruction is preceeded by the WIDE (widening)
746      *            instruction.
747      */
748 
749     public CLArithmeticInstruction(int opcode, int pc, int localVariableIndex,
750             int constVal, boolean isWidened) {
751         super.opcode = opcode;
752         super.pc = pc;
753         super.localVariableIndex = localVariableIndex;
754         mnemonic = instructionInfo[opcode].mnemonic;
755         operandCount = instructionInfo[opcode].operandCount;
756         stackUnits = instructionInfo[opcode].stackUnits;
757         this.constVal = constVal;
758         this.isWidened = isWidened;
759     }
760 
761     /**
762      * @inheritDoc
763      */
764 
765     public ArrayList<Integer> toBytes() {
766         ArrayList<Integer> bytes = new ArrayList<Integer>();
767         bytes.add(opcode);
768         if (opcode == IINC) {
769             if (isWidened) {
770                 bytes.add(byteAt(localVariableIndex, 2));
771                 bytes.add(byteAt(localVariableIndex, 1));
772                 bytes.add(byteAt(constVal, 2));
773                 bytes.add(byteAt(constVal, 1));
774             } else {
775                 bytes.add(byteAt(localVariableIndex, 1));
776                 bytes.add(byteAt(constVal, 1));
777             }
778         }
779         return bytes;
780     }
781 
782 }
783 
784 /**
785  * Representation for BIT instructions.
786  */
787 
788 class CLBitInstruction extends CLInstruction {
789 
790     /**
791      * Construct a CLBitInstruction object.
792      * 
793      * @param opcode
794      *            the opcode for this instruction.
795      * @param pc
796      *            index of this instruction within the code array of a method.
797      */
798 
799     public CLBitInstruction(int opcode, int pc) {
800         super.opcode = opcode;
801         super.pc = pc;
802         mnemonic = instructionInfo[opcode].mnemonic;
803         operandCount = instructionInfo[opcode].operandCount;
804         stackUnits = instructionInfo[opcode].stackUnits;
805         localVariableIndex = instructionInfo[opcode].localVariableIndex;
806     }
807 
808     /**
809      * @inheritDoc
810      */
811 
812     public ArrayList<Integer> toBytes() {
813         ArrayList<Integer> bytes = new ArrayList<Integer>();
814         bytes.add(opcode);
815         return bytes;
816     }
817 
818 }
819 
820 /**
821  * Representation for COMPARISON instructions.
822  */
823 
824 class CLComparisonInstruction extends CLInstruction {
825 
826     /**
827      * Construct a CLComparisonInstruction object.
828      * 
829      * @param opcode
830      *            the opcode for this instruction.
831      * @param pc
832      *            index of this instruction within the code array of a method.
833      */
834 
835     public CLComparisonInstruction(int opcode, int pc) {
836         super.opcode = opcode;
837         super.pc = pc;
838         mnemonic = instructionInfo[opcode].mnemonic;
839         operandCount = instructionInfo[opcode].operandCount;
840         stackUnits = instructionInfo[opcode].stackUnits;
841         localVariableIndex = instructionInfo[opcode].localVariableIndex;
842     }
843 
844     /**
845      * @inheritDoc
846      */
847 
848     public ArrayList<Integer> toBytes() {
849         ArrayList<Integer> bytes = new ArrayList<Integer>();
850         bytes.add(opcode);
851         return bytes;
852     }
853 
854 }
855 
856 /**
857  * Representation for CONVERSION instructions.
858  */
859 
860 class CLConversionInstruction extends CLInstruction {
861 
862     /**
863      * Construct a CLConversionInstruction object.
864      * 
865      * @param opcode
866      *            the opcode for this instruction.
867      * @param pc
868      *            index of this instruction within the code array of a method.
869      */
870 
871     public CLConversionInstruction(int opcode, int pc) {
872         super.opcode = opcode;
873         super.pc = pc;
874         mnemonic = instructionInfo[opcode].mnemonic;
875         operandCount = instructionInfo[opcode].operandCount;
876         stackUnits = instructionInfo[opcode].stackUnits;
877         localVariableIndex = instructionInfo[opcode].localVariableIndex;
878     }
879 
880     /**
881      * @inheritDoc
882      */
883 
884     public ArrayList<Integer> toBytes() {
885         ArrayList<Integer> bytes = new ArrayList<Integer>();
886         bytes.add(opcode);
887         return bytes;
888     }
889 
890 }
891 
892 /**
893  * Representation for FLOW_CONTROL1, FLOW_CONTROL2, FLOW_CONTROL3 and
894  * FLOW_CONTROL4 instructions.
895  */
896 
897 class CLFlowControlInstruction extends CLInstruction {
898 
899     /**
900      * Jump label; this flow control instruction will jump to an instruction
901      * after this label.
902      */
903     private String jumpToLabel;
904 
905     /** jumpLabel is resolved to this offset. */
906     private int jumpToOffset;
907 
908     /**
909      * Index of the local variable containing the return address; applies only
910      * to RET instruction.
911      */
912     private int index;
913 
914     /**
915      * Whether this instruction is preceeded by a WIDE instruction; applies only
916      * to RET instruction.
917      */
918     private boolean isWidened;
919 
920     /**
921      * These many (0-3) bytes are added before default offset so that the index
922      * of the offset is divisible by 4.
923      */
924     private int pad;
925 
926     /**
927      * Jump label for default value for TABLESWITCH and LOOKUPSWITCH
928      * instructions.
929      */
930     private String defaultLabel;
931 
932     /** defaultLabel is resolved to this offset. */
933     private int defaultOffset;
934 
935     /**
936      * Number of pairs in the match table for LOOKUPSWITCH instruction.
937      */
938     private int numPairs;
939 
940     /** Key and label table for LOOKUPSWITCH instruction. */
941     private TreeMap<Integer, String> matchLabelPairs;
942 
943     /**
944      * Key and offset (resolved labels from matchLabelPairs) table for
945      * LOOKUPSWITCH instruction.
946      */
947     private TreeMap<Integer, Integer> matchOffsetPairs;
948 
949     /** Smallest value of index for TABLESWITCH instruction. */
950     private int low;
951 
952     /** Highest value of index for TABLESWITCH instruction. */
953     private int high;
954 
955     /**
956      * List of jump labels for TABLESWITCH instruction for each index value from
957      * low to high, end values included.
958      */
959     private ArrayList<String> labels;
960 
961     /**
962      * List of offsets (resolved labels from labels) for TABLESWITCH
963      * instruction.
964      */
965     private ArrayList<Integer> offsets;
966 
967     /**
968      * Construct a CLFlowControlInstruction object for FLOW_CONTROL1
969      * instructions.
970      * 
971      * @param opcode
972      *            the opcode for this instruction.
973      * @param pc
974      *            index of this instruction within the code array of a method.
975      * @param jumpToLabel
976      *            the label to jump to.
977      */
978 
979     public CLFlowControlInstruction(int opcode, int pc, String jumpToLabel) {
980         super.opcode = opcode;
981         super.pc = pc;
982         mnemonic = instructionInfo[opcode].mnemonic;
983         operandCount = instructionInfo[opcode].operandCount;
984         stackUnits = instructionInfo[opcode].stackUnits;
985         localVariableIndex = instructionInfo[opcode].localVariableIndex;
986         this.jumpToLabel = jumpToLabel;
987     }
988 
989     /**
990      * Construct a CLFlowControlInstruction object for RET instruction.
991      * 
992      * @param pc
993      *            index of this instruction within the code array of a method.
994      * @param index
995      *            index of the local variable containing the return address.
996      * @param isWidened
997      *            whether this instruction is preceeded by the WIDE (widening)
998      *            instruction.
999      */
1000
1001    public CLFlowControlInstruction(int pc, int index, boolean isWidened) {
1002        super.opcode = RET;
1003        super.pc = pc;
1004        mnemonic = instructionInfo[opcode].mnemonic;
1005        operandCount = instructionInfo[opcode].operandCount;
1006        stackUnits = instructionInfo[opcode].stackUnits;
1007        localVariableIndex = instructionInfo[opcode].localVariableIndex;
1008        this.index = index;
1009        this.isWidened = isWidened;
1010    }
1011
1012    /**
1013     * Construct a CLFlowControlInstruction object for TABLESWITCH instruction.
1014     * 
1015     * @param opcode
1016     *            the opcode for this instruction.
1017     * @param pc
1018     *            index of this instruction within the code array of a method.
1019     * @param defaultLabel
1020     *            jump label for default value.
1021     * @param low
1022     *            smallest value of index.
1023     * @param high
1024     *            highest value of index.
1025     * @param labels
1026     *            list of jump labels for each index value from low to high, end
1027     *            values included.
1028     */
1029
1030    public CLFlowControlInstruction(int opcode, int pc, String defaultLabel,
1031            int low, int high, ArrayList<String> labels) {
1032        super.opcode = opcode;
1033        super.pc = pc;
1034        mnemonic = instructionInfo[opcode].mnemonic;
1035        stackUnits = instructionInfo[opcode].stackUnits;
1036        localVariableIndex = instructionInfo[opcode].localVariableIndex;
1037        this.defaultLabel = defaultLabel;
1038        this.low = low;
1039        this.high = high;
1040        this.labels = labels;
1041        pad = 4 - ((pc + 1) % 4);
1042        operandCount = pad + 12 + 4 * labels.size();
1043    }
1044
1045    /**
1046     * Construct a CLFlowControlInstruction object for LOOKUPSWITCH instruction.
1047     * 
1048     * @param opcode
1049     *            the opcode for this instruction.
1050     * @param pc
1051     *            index of this instruction within the code array of a method.
1052     * @param defaultLabel
1053     *            jump label for default value.
1054     * @param numPairs
1055     *            number of pairs in the match table.
1056     * @param matchLabelPairs
1057     *            key match table.
1058     */
1059
1060    public CLFlowControlInstruction(int opcode, int pc, String defaultLabel,
1061            int numPairs, TreeMap<Integer, String> matchLabelPairs) {
1062        super.opcode = opcode;
1063        super.pc = pc;
1064        mnemonic = instructionInfo[opcode].mnemonic;
1065        stackUnits = instructionInfo[opcode].stackUnits;
1066        localVariableIndex = instructionInfo[opcode].localVariableIndex;
1067        this.defaultLabel = defaultLabel;
1068        this.numPairs = numPairs;
1069        this.matchLabelPairs = matchLabelPairs;
1070        pad = 4 - ((pc + 1) % 4);
1071        operandCount = pad + 8 + 8 * numPairs;
1072    }
1073
1074    /**
1075     * Resolve the jump labels to the corresponding offset values using the
1076     * given label to pc mapping. If unable to resolve a label, the offset is
1077     * set such that the next instruction will be executed.
1078     * 
1079     * @param labelToPC
1080     *            label to pc mapping.
1081     * @return true if all labels were resolved successfully; false otherwise.
1082     */
1083
1084    public boolean resolveLabels(Hashtable<String, Integer> labelToPC) {
1085        boolean allLabelsResolved = true;
1086        if (instructionInfo[opcode].category == FLOW_CONTROL1) {
1087            if (labelToPC.containsKey(jumpToLabel)) {
1088                jumpToOffset = labelToPC.get(jumpToLabel) - pc;
1089            } else {
1090                jumpToOffset = operandCount;
1091                allLabelsResolved = false;
1092            }
1093        } else if (opcode == LOOKUPSWITCH) {
1094            if (labelToPC.containsKey(defaultLabel)) {
1095                defaultOffset = labelToPC.get(defaultLabel) - pc;
1096            } else {
1097                defaultOffset = operandCount;
1098                allLabelsResolved = false;
1099            }
1100            matchOffsetPairs = new TreeMap<Integer, Integer>();
1101            Set<Entry<Integer, String>> matches = matchLabelPairs.entrySet();
1102            Iterator<Entry<Integer, String>> iter = matches.iterator();
1103            while (iter.hasNext()) {
1104                Entry<Integer, String> entry = iter.next();
1105                int match = entry.getKey();
1106                String label = entry.getValue();
1107                if (labelToPC.containsKey(label)) {
1108                    matchOffsetPairs.put(match, labelToPC.get(label) - pc);
1109                } else {
1110                    matchOffsetPairs.put(match, operandCount);
1111                    allLabelsResolved = false;
1112                }
1113            }
1114        } else if (opcode == TABLESWITCH) {
1115            if (labelToPC.containsKey(defaultLabel)) {
1116                defaultOffset = labelToPC.get(defaultLabel) - pc;
1117            } else {
1118                defaultOffset = operandCount;
1119                allLabelsResolved = false;
1120            }
1121            offsets = new ArrayList<Integer>();
1122            for (int i = 0; i < labels.size(); i++) {
1123                if (labelToPC.containsKey(labels.get(i))) {
1124                    offsets.add(labelToPC.get(labels.get(i)) - pc);
1125                } else {
1126                    offsets.add(operandCount);
1127                    allLabelsResolved = false;
1128                }
1129            }
1130        }
1131        return allLabelsResolved;
1132    }
1133
1134    /**
1135     * Return the pc of instruction to jump to.
1136     * 
1137     * @return pc to jump to.
1138     */
1139
1140    public int jumpToOffset() {
1141        return jumpToOffset;
1142    }
1143
1144    /**
1145     * @inheritDoc
1146     */
1147
1148    public ArrayList<Integer> toBytes() {
1149        ArrayList<Integer> bytes = new ArrayList<Integer>();
1150        bytes.add(opcode);
1151        switch (opcode) {
1152        case RET:
1153            if (isWidened) {
1154                bytes.add(byteAt(index, 2));
1155                bytes.add(byteAt(index, 1));
1156            } else {
1157                bytes.add(byteAt(index, 1));
1158            }
1159            break;
1160        case TABLESWITCH:
1161            for (int i = 0; i < pad; i++) {
1162                bytes.add(0);
1163            }
1164            bytes.add(byteAt(defaultOffset, 4));
1165            bytes.add(byteAt(defaultOffset, 3));
1166            bytes.add(byteAt(defaultOffset, 2));
1167            bytes.add(byteAt(defaultOffset, 1));
1168            bytes.add(byteAt(low, 4));
1169            bytes.add(byteAt(low, 3));
1170            bytes.add(byteAt(low, 2));
1171            bytes.add(byteAt(low, 1));
1172            bytes.add(byteAt(high, 4));
1173            bytes.add(byteAt(high, 3));
1174            bytes.add(byteAt(high, 2));
1175            bytes.add(byteAt(high, 1));
1176            for (int i = 0; i < offsets.size(); i++) {
1177                int jumpOffset = offsets.get(i);
1178                bytes.add(byteAt(jumpOffset, 4));
1179                bytes.add(byteAt(jumpOffset, 3));
1180                bytes.add(byteAt(jumpOffset, 2));
1181                bytes.add(byteAt(jumpOffset, 1));
1182            }
1183            break;
1184        case LOOKUPSWITCH:
1185            for (int i = 0; i < pad; i++) {
1186                bytes.add(0);
1187            }
1188            bytes.add(byteAt(defaultOffset, 4));
1189            bytes.add(byteAt(defaultOffset, 3));
1190            bytes.add(byteAt(defaultOffset, 2));
1191            bytes.add(byteAt(defaultOffset, 1));
1192            bytes.add(byteAt(numPairs, 4));
1193            bytes.add(byteAt(numPairs, 3));
1194            bytes.add(byteAt(numPairs, 2));
1195            bytes.add(byteAt(numPairs, 1));
1196            Set<Entry<Integer, Integer>> matches = matchOffsetPairs.entrySet();
1197            Iterator<Entry<Integer, Integer>> iter = matches.iterator();
1198            while (iter.hasNext()) {
1199                Entry<Integer, Integer> entry = iter.next();
1200                int match = entry.getKey();
1201                int offset = entry.getValue();
1202                bytes.add(byteAt(match, 4));
1203                bytes.add(byteAt(match, 3));
1204                bytes.add(byteAt(match, 2));
1205                bytes.add(byteAt(match, 1));
1206                bytes.add(byteAt(offset, 4));
1207                bytes.add(byteAt(offset, 3));
1208                bytes.add(byteAt(offset, 2));
1209                bytes.add(byteAt(offset, 1));
1210            }
1211            break;
1212        case GOTO_W:
1213        case JSR_W:
1214            bytes.add(byteAt(jumpToOffset, 4));
1215            bytes.add(byteAt(jumpToOffset, 3));
1216            bytes.add(byteAt(jumpToOffset, 2));
1217            bytes.add(byteAt(jumpToOffset, 1));
1218            break;
1219        default:
1220            bytes.add(byteAt(jumpToOffset, 2));
1221            bytes.add(byteAt(jumpToOffset, 1));
1222        }
1223        return bytes;
1224    }
1225
1226}
1227
1228/**
1229 * Representation for LOAD_STORE1, LOAD_STORE2, LOAD_STORE3 and LOAD_STORE4
1230 * instructions.
1231 */
1232
1233class CLLoadStoreInstruction extends CLInstruction {
1234
1235    /**
1236     * Whether this instruction is preceeded by a WIDE instruction; applies only
1237     * to ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE,
1238     * ASTORE.
1239     */
1240    private boolean isWidened;
1241
1242    /**
1243     * A byte (for BIPUSH), a short (for SIPUSH), or a constant pool index for
1244     * LDC, LDC_W, LDC2_W instructions.
1245     */
1246    private int constVal;
1247
1248    /**
1249     * Construct a CLLoadStoreInstruction object for LOAD_STORE1 instructions.
1250     * 
1251     * @param opcode
1252     *            the opcode for this instruction.
1253     * @param pc
1254     *            index of this instruction within the code array of a method.
1255     */
1256
1257    public CLLoadStoreInstruction(int opcode, int pc) {
1258        super.opcode = opcode;
1259        super.pc = pc;
1260        mnemonic = instructionInfo[opcode].mnemonic;
1261        operandCount = instructionInfo[opcode].operandCount;
1262        stackUnits = instructionInfo[opcode].stackUnits;
1263        localVariableIndex = instructionInfo[opcode].localVariableIndex;
1264    }
1265
1266    /**
1267     * Construct a CLLoadStoreInstruction object for LOAD_STORE2 instructions.
1268     * 
1269     * @param opcode
1270     *            the opcode for this instruction.
1271     * @param pc
1272     *            index of this instruction within the code array of a method.
1273     * @param localVariableIndex
1274     *            index of the local variable to increment.
1275     * @param isWidened
1276     *            whether this instruction is preceeded by the WIDE (widening)
1277     *            instruction.
1278     */
1279
1280    public CLLoadStoreInstruction(int opcode, int pc, int localVariableIndex,
1281            boolean isWidened) {
1282        super.opcode = opcode;
1283        super.pc = pc;
1284        mnemonic = instructionInfo[opcode].mnemonic;
1285        operandCount = instructionInfo[opcode].operandCount;
1286        stackUnits = instructionInfo[opcode].stackUnits;
1287        super.localVariableIndex = localVariableIndex;
1288        this.isWidened = isWidened;
1289    }
1290
1291    /**
1292     * Construct a CLLoadStoreInstruction object for LOAD_STORE3 and LOAD_STORE4
1293     * instructions.
1294     * 
1295     * @param opcode
1296     *            the opcode for this instruction.
1297     * @param pc
1298     *            index of this instruction within the code array of a method.
1299     * @param constVal
1300     *            a byte (for BIPUSH), a short (for SIPUSH), or a constant pool
1301     *            index for LDC instructions.
1302     */
1303
1304    public CLLoadStoreInstruction(int opcode, int pc, int constVal) {
1305        super.opcode = opcode;
1306        super.pc = pc;
1307        mnemonic = instructionInfo[opcode].mnemonic;
1308        operandCount = instructionInfo[opcode].operandCount;
1309        stackUnits = instructionInfo[opcode].stackUnits;
1310        localVariableIndex = instructionInfo[opcode].localVariableIndex;
1311        this.constVal = constVal;
1312    }
1313
1314    /**
1315     * @inheritDoc
1316     */
1317
1318    public ArrayList<Integer> toBytes() {
1319        ArrayList<Integer> bytes = new ArrayList<Integer>();
1320        bytes.add(opcode);
1321        if (instructionInfo[opcode].operandCount > 0) {
1322            if (localVariableIndex != IRRELEVANT) {
1323                if (isWidened) {
1324                    bytes.add(byteAt(localVariableIndex, 2));
1325                }
1326                bytes.add(byteAt(localVariableIndex, 1));
1327            } else {
1328                switch (opcode) {
1329                case BIPUSH:
1330                case LDC:
1331                    bytes.add(byteAt(constVal, 1));
1332                    break;
1333                case SIPUSH:
1334                case LDC_W:
1335                case LDC2_W:
1336                    bytes.add(byteAt(constVal, 2));
1337                    bytes.add(byteAt(constVal, 1));
1338                }
1339            }
1340        }
1341        return bytes;
1342    }
1343
1344}
1345
1346/**
1347 * Representation for STACK instructions.
1348 */
1349
1350class CLStackInstruction extends CLInstruction {
1351
1352    /**
1353     * Construct a CLStackInstruction object.
1354     * 
1355     * @param opcode
1356     *            the opcode for this instruction.
1357     * @param pc
1358     *            index of this instruction within the code array of a method.
1359     */
1360
1361    public CLStackInstruction(int opcode, int pc) {
1362        super.opcode = opcode;
1363        super.pc = pc;
1364        mnemonic = instructionInfo[opcode].mnemonic;
1365        operandCount = instructionInfo[opcode].operandCount;
1366        stackUnits = instructionInfo[opcode].stackUnits;
1367        localVariableIndex = instructionInfo[opcode].localVariableIndex;
1368    }
1369
1370    /**
1371     * @inheritDoc
1372     */
1373
1374    public ArrayList<Integer> toBytes() {
1375        ArrayList<Integer> bytes = new ArrayList<Integer>();
1376        bytes.add(opcode);
1377        return bytes;
1378    }
1379
1380}
1381
1382/**
1383 * Representation for MISC instructions.
1384 */
1385
1386class CLMiscInstruction extends CLInstruction {
1387
1388    /**
1389     * Construct a CLMiscInstruction object.
1390     * 
1391     * @param opcode
1392     *            the opcode for this instruction.
1393     * @param pc
1394     *            index of this instruction within the code array of a method.
1395     */
1396
1397    public CLMiscInstruction(int opcode, int pc) {
1398        super.opcode = opcode;
1399        super.pc = pc;
1400        mnemonic = instructionInfo[opcode].mnemonic;
1401        operandCount = instructionInfo[opcode].operandCount;
1402        stackUnits = instructionInfo[opcode].stackUnits;
1403        localVariableIndex = instructionInfo[opcode].localVariableIndex;
1404    }
1405
1406    /**
1407     * @inheritDoc
1408     */
1409
1410    public ArrayList<Integer> toBytes() {
1411        ArrayList<Integer> bytes = new ArrayList<Integer>();
1412        bytes.add(opcode);
1413        return bytes;
1414    }
1415
1416}
1417
1418/**
1419 * This class stores static information about a JVM instruction.
1420 */
1421
1422class CLInsInfo {
1423
1424    /** Opcode for this instruction. */
1425    public int opcode;
1426
1427    /** Mnemonic for this instruction. */
1428    public String mnemonic;
1429
1430    /** Number of operands for this instruction. */
1431    public int operandCount;
1432
1433    /**
1434     * Words produced - words consumed from the operand stack by this
1435     * instruction.
1436     */
1437    public int stackUnits;
1438
1439    /**
1440     * Index of the local variable that this instruction refers to; applies only
1441     * to instructions that operate on local variables.
1442     */
1443    public int localVariableIndex;
1444
1445    /** The category under which instruction belongs. */
1446    public Category category;
1447
1448    /**
1449     * Construct a CLInsInfo object.
1450     * 
1451     * @param opcode
1452     *            opcode for this instruction.
1453     * @param mnemonic
1454     *            name for this instruction.
1455     * @param operandCount
1456     *            number of operands for this instruction.
1457     * @param localVariableIndex
1458     *            index of the local variable that this instruction refers to.
1459     * @param stackUnits
1460     *            words produced - words consumed from the operand stack by this
1461     *            instruction.
1462     * @param category
1463     *            category under which this instruction belogs.
1464     */
1465
1466    public CLInsInfo(int opcode, String mnemonic, int operandCount,
1467            int localVariableIndex, int stackUnits, Category category) {
1468        this.opcode = opcode;
1469        this.mnemonic = mnemonic;
1470        this.operandCount = operandCount;
1471        this.localVariableIndex = localVariableIndex;
1472        this.stackUnits = stackUnits;
1473        this.category = category;
1474    }
1475
1476}
1477