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