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