001    package edu.rice.cs.cunit.classFile.code.instructions;
002    
003    import edu.rice.cs.cunit.classFile.code.Opcode;
004    import edu.rice.cs.cunit.classFile.constantPool.ConstantPool;
005    
006    /**
007     * Abstract Java instruction.
008     *
009     * @author Mathias Ricken
010     */
011    public abstract class AInstruction {
012        /**
013         * Get the bytecode for this instruction, padded for the specified program counter value, with branch targets
014         * according to the specified line number table
015         *
016         * @param pc  PC for padding
017         * @param lnt line number table for branches
018         *
019         * @return bytecode
020         */
021        public abstract byte[] getBytecode(int pc, LineNumberTable lnt);
022    
023        /**
024         * Get the opcode of this instruction.
025         *
026         * @return opcode
027         */
028        public abstract byte getOpcode();
029    
030        /**
031         * Get the length bytecode for this instruction, padded for the specified program counter value.
032         *
033         * @param pc PC for padding
034         *
035         * @return bytecode length
036         */
037        public abstract int getBytecodeLength(int pc);
038    
039        /**
040         * Return an array of target indices.
041         *
042         * @return array of target indices.
043         */
044        public abstract int[] getBranchTargets();
045    
046        /**
047         * Set the branch target indices.
048         *
049         * @param branchTargets array of target indices
050         */
051        public abstract void setBranchTargets(int[] branchTargets);
052    
053        /**
054         * Make an instruction from the bytecode starting at pc, using the specified padding PC and the line number table.
055         *
056         * @param bytecode  bytecode
057         * @param pc        start PC in bytecode
058         * @param paddingPC PC used for padding
059         * @param lnt       line number table for branches
060         *
061         * @return instruction
062         */
063        public static AInstruction makeInstruction(byte[] bytecode, int pc, int paddingPC, LineNumberTable lnt) {
064            byte o = bytecode[pc];
065            switch(o) {
066                case Opcode.TABLESWITCH:
067                    return new TableSwitchInstruction(bytecode, pc, paddingPC, lnt);
068    
069                case Opcode.LOOKUPSWITCH:
070                    return new LookupSwitchInstruction(bytecode, pc, paddingPC, lnt);
071    
072                case Opcode.IFEQ:
073                case Opcode.IFNE:
074                case Opcode.IFLT:
075                case Opcode.IFGE:
076                case Opcode.IFGT:
077                case Opcode.IFLE:
078                case Opcode.IF_ICMPEQ:
079                case Opcode.IF_ICMPNE:
080                case Opcode.IF_ICMPLT:
081                case Opcode.IF_ICMPGE:
082                case Opcode.IF_ICMPGT:
083                case Opcode.IF_ICMPLE:
084                case Opcode.IF_ACMPEQ:
085                case Opcode.IF_ACMPNE:
086                case Opcode.GOTO:
087                case Opcode.JSR:
088                case Opcode.IFNULL:
089                case Opcode.IFNONNULL:
090                    return new BranchInstruction(bytecode, pc, paddingPC, lnt);
091    
092                case Opcode.GOTO_W:
093                case Opcode.JSR_W:
094                    return new WideBranchInstruction(bytecode, pc, paddingPC, lnt);
095    
096                case Opcode.WIDE:
097                    return new WideInstruction(bytecode, pc, paddingPC, lnt);
098    
099                case Opcode.INVOKESTATIC:
100                case Opcode.INVOKESPECIAL:
101                case Opcode.INVOKEVIRTUAL:
102                case Opcode.CHECKCAST:
103                case Opcode.GETFIELD:
104                case Opcode.GETSTATIC:
105                case Opcode.INSTANCEOF:
106                case Opcode.NEW:
107                case Opcode.PUTFIELD:
108                case Opcode.PUTSTATIC:
109                case Opcode.ANEWARRAY:
110                case Opcode.LDC:
111                case Opcode.LDC_W:
112                case Opcode.LDC2_W:
113                    return new ReferenceInstruction(bytecode, pc, paddingPC, lnt);
114    
115                default:
116                    return new GenericInstruction(bytecode, pc, paddingPC, lnt);
117            }
118        }
119    
120        /**
121         * Return true of this instruction and the other object are equal.
122         *
123         * @param o other object
124         *
125         * @return true if equal
126         */
127        public abstract boolean equals(Object o);
128    
129        /**
130         * Return hash code.
131         *
132         * @return hash code
133         */
134        public abstract int hashCode();
135    
136        /**
137         * Return a verbose string representation.
138         * @param cp constant pool
139         * @return verbose string representation
140         */
141        public String toStringVerbose(ConstantPool cp) {
142            return toString();
143        }
144    
145        /**
146         * Returns a store instruction that corresponds to the given load instruction.
147         * @param loadInstruction load instruction
148         * @return corresponding store instruction
149         */
150        public static AInstruction getCorrespondingStore(AInstruction loadInstruction) {
151            byte opcode = loadInstruction.getOpcode();
152            if (opcode==Opcode.WIDE) {
153                WideInstruction wi = (WideInstruction)loadInstruction;
154                byte[] code = wi.getBytecode();
155                byte opcode2 = code[1];
156                if ((opcode2>=Opcode.ILOAD) && (opcode2<=Opcode.ALOAD)) {
157                    // WIDE ILOAD 0x15 -> WIDE ISTORE 0x36;
158                    // WIDE LLOAD 0x16 -> WIDE LSTORE 0x37;
159                    // WIDE FLOAD 0x17 -> WIDE FSTORE 0x38;
160                    // WIDE DLOAD 0x18 -> WIDE DSTORE 0x39;
161                    // WIDE ALOAD 0x19 -> WIDE ASTORE 0x3A;
162                    return new WideInstruction(new byte[] {(byte)(opcode2 + (Opcode.ISTORE-Opcode.ILOAD)), code[2], code[3]});
163                }
164            }
165            else if ((opcode>=Opcode.ILOAD) && (opcode<=Opcode.ALOAD)) {
166                // ILOAD 0x15 -> ISTORE 0x36;
167                // LLOAD 0x16 -> LSTORE 0x37;
168                // FLOAD 0x17 -> FSTORE 0x38;
169                // DLOAD 0x18 -> DSTORE 0x39;
170                // ALOAD 0x19 -> ASTORE 0x3A;
171                GenericInstruction gi = (GenericInstruction)loadInstruction;
172                byte[] code = gi.getBytecode();
173                return new GenericInstruction(new byte[] {(byte)(opcode + (Opcode.ISTORE-Opcode.ILOAD)), code[1]});
174            }
175            else if ((opcode>=Opcode.ILOAD_0) && (opcode<=Opcode.ALOAD_3)) {
176                // ILOAD_0 0x1A -> ISTORE_0 0x3B;
177                // ILOAD_1 0x1B -> ISTORE_1 0x3C;
178                // ILOAD_2 0x1C -> ISTORE_2 0x3D;
179                // ILOAD_3 0x1D -> ISTORE_3 0x3E;
180                // LLOAD_0 0x1E -> LSTORE_0 0x3F;
181                // LLOAD_1 0x1F -> LSTORE_1 0x40;
182                // LLOAD_2 0x20 -> LSTORE_2 0x41;
183                // LLOAD_3 0x21 -> LSTORE_3 0x42;
184                // FLOAD_0 0x22 -> FSTORE_0 0x43;
185                // FLOAD_1 0x23 -> FSTORE_1 0x44;
186                // FLOAD_2 0x24 -> FSTORE_2 0x45;
187                // FLOAD_3 0x25 -> FSTORE_3 0x46;
188                // DLOAD_0 0x26 -> DSTORE_0 0x47;
189                // DLOAD_1 0x27 -> DSTORE_1 0x48;
190                // DLOAD_2 0x28 -> DSTORE_2 0x49;
191                // DLOAD_3 0x29 -> DSTORE_3 0x4A;
192                // ALOAD_0 0x2A -> ASTORE_0 0x4B;
193                // ALOAD_1 0x2B -> ASTORE_1 0x4C;
194                // ALOAD_2 0x2C -> ASTORE_2 0x4D;
195                // ALOAD_3 0x2D -> ASTORE_3 0x4E;
196                return new GenericInstruction(new byte[] {(byte)(opcode + (Opcode.ISTORE_0-Opcode.ILOAD_0))});
197            }
198            else if ((opcode>=Opcode.IALOAD) && (opcode<=Opcode.SALOAD)) {
199                // IALOAD 0x2E -> IASTORE 0x4F;
200                // LALOAD 0x2F -> LASTORE 0x50;
201                // FALOAD 0x30 -> FASTORE 0x51;
202                // DALOAD 0x31 -> DASTORE 0x52;
203                // AALOAD 0x32 -> AASTORE 0x53;
204                // BALOAD 0x33 -> BASTORE 0x54;
205                // CALOAD 0x34 -> CASTORE 0x55;
206                // SALOAD 0x35 -> SASTORE 0x56;
207                GenericInstruction gi = (GenericInstruction)loadInstruction;
208                byte[] code = gi.getBytecode();
209                return new GenericInstruction(new byte[] {(byte)(opcode + (Opcode.ISTORE-Opcode.ILOAD))});
210            }
211            throw new IllegalArgumentException("Invalid load instruction");
212        }
213    
214        /**
215         * Returns a load instruction that corresponds to the given store instruction.
216         * @param storeInstruction store instruction
217         * @return corresponding load instruction
218         */
219        public static AInstruction getCorrespondingLoad(AInstruction storeInstruction) {
220            byte opcode = storeInstruction.getOpcode();
221            if (opcode==Opcode.WIDE) {
222                WideInstruction wi = (WideInstruction)storeInstruction;
223                byte[] code = wi.getBytecode();
224                byte opcode2 = code[1];
225                if ((opcode2>=Opcode.ISTORE) && (opcode2<=Opcode.ASTORE)) {
226                    // WIDE ISTORE 0x36 -> WIDE ILOAD 0x15;
227                    // WIDE LSTORE 0x37 -> WIDE LLOAD 0x16;
228                    // WIDE FSTORE 0x38 -> WIDE FLOAD 0x17;
229                    // WIDE DSTORE 0x39 -> WIDE DLOAD 0x18;
230                    // WIDE ASTORE 0x3A -> WIDE ALOAD 0x19;
231                    return new WideInstruction(new byte[] {(byte)(opcode2 - (Opcode.ISTORE-Opcode.ILOAD)), code[2], code[3]});
232                }
233            }
234            else if ((opcode>=Opcode.ISTORE) && (opcode<=Opcode.ASTORE)) {
235                // ISTORE 0x36 -> ILOAD 0x15;
236                // LSTORE 0x37 -> LLOAD 0x16;
237                // FSTORE 0x38 -> FLOAD 0x17;
238                // DSTORE 0x39 -> DLOAD 0x18;
239                // ASTORE 0x3A -> ALOAD 0x19;
240                GenericInstruction gi = (GenericInstruction)storeInstruction;
241                byte[] code = gi.getBytecode();
242                return new GenericInstruction(new byte[] {(byte)(opcode - (Opcode.ISTORE-Opcode.ILOAD)), code[1]});
243            }
244            else if ((opcode>=Opcode.ISTORE_0) && (opcode<=Opcode.ASTORE_3)) {
245                // ISTORE_0 0x3B -> ILOAD_0 0x1A;
246                // ISTORE_1 0x3C -> ILOAD_1 0x1B;
247                // ISTORE_2 0x3D -> ILOAD_2 0x1C;
248                // ISTORE_3 0x3E -> ILOAD_3 0x1D;
249                // LSTORE_0 0x3F -> LLOAD_0 0x1E;
250                // LSTORE_1 0x40 -> LLOAD_1 0x1F;
251                // LSTORE_2 0x41 -> LLOAD_2 0x20;
252                // LSTORE_3 0x42 -> LLOAD_3 0x21;
253                // FSTORE_0 0x43 -> FLOAD_0 0x22;
254                // FSTORE_1 0x44 -> FLOAD_1 0x23;
255                // FSTORE_2 0x45 -> FLOAD_2 0x24;
256                // FSTORE_3 0x46 -> FLOAD_3 0x25;
257                // DSTORE_0 0x47 -> DLOAD_0 0x26;
258                // DSTORE_1 0x48 -> DLOAD_1 0x27;
259                // DSTORE_2 0x49 -> DLOAD_2 0x28;
260                // DSTORE_3 0x4A -> DLOAD_3 0x29;
261                // ASTORE_0 0x4B -> ALOAD_0 0x2A;
262                // ASTORE_1 0x4C -> ALOAD_1 0x2B;
263                // ASTORE_2 0x4D -> ALOAD_2 0x2C;
264                // ASTORE_3 0x4E -> ALOAD_3 0x2D;
265                return new GenericInstruction(new byte[] {(byte)(opcode - (Opcode.ISTORE_0-Opcode.ILOAD_0))});
266            }
267            else if ((opcode>=Opcode.IASTORE) && (opcode<=Opcode.SASTORE)) {
268                // IASTORE 0x4F -> IALOAD 0x2E;
269                // LASTORE 0x50 -> LALOAD 0x2F;
270                // FASTORE 0x51 -> FALOAD 0x30;
271                // DASTORE 0x52 -> DALOAD 0x31;
272                // AASTORE 0x53 -> AALOAD 0x32;
273                // BASTORE 0x54 -> BALOAD 0x33;
274                // CASTORE 0x55 -> CALOAD 0x34;
275                // SASTORE 0x56 -> SALOAD 0x35;
276                GenericInstruction gi = (GenericInstruction)storeInstruction;
277                byte[] code = gi.getBytecode();
278                return new GenericInstruction(new byte[] {(byte)(opcode - (Opcode.IASTORE-Opcode.IALOAD))});
279            }
280            throw new IllegalArgumentException("Invalid store instruction");
281        }
282    }
283