001    package edu.rice.cs.cunit.classFile.code.instructions;
002    
003    import edu.rice.cs.cunit.classFile.code.Opcode;
004    
005    import java.util.Arrays;
006    
007    /**
008     * Generic Java instruction.
009     *
010     * @author Mathias Ricken
011     */
012    public class GenericInstruction extends AInstruction {
013        /**
014         * Bytecode.
015         */
016        protected byte[] _code;
017    
018        /**
019         * Constructor.
020         *
021         * @param code bytecode for generic instruction
022         */
023        public GenericInstruction(byte... code) {
024            switch(code[0]) {
025                case Opcode.TABLESWITCH:
026                case Opcode.LOOKUPSWITCH:
027                case Opcode.IFEQ:
028                case Opcode.IFNE:
029                case Opcode.IFLT:
030                case Opcode.IFGE:
031                case Opcode.IFGT:
032                case Opcode.IFLE:
033                case Opcode.IF_ICMPEQ:
034                case Opcode.IF_ICMPNE:
035                case Opcode.IF_ICMPLT:
036                case Opcode.IF_ICMPGE:
037                case Opcode.IF_ICMPGT:
038                case Opcode.IF_ICMPLE:
039                case Opcode.IF_ACMPEQ:
040                case Opcode.IF_ACMPNE:
041                case Opcode.GOTO:
042                case Opcode.JSR:
043                case Opcode.IFNULL:
044                case Opcode.IFNONNULL:
045                case Opcode.GOTO_W:
046                case Opcode.JSR_W:
047                case Opcode.WIDE:
048                    throw new IllegalArgumentException("Invalid generic opcode");
049            }
050            _code = code;
051        }
052    
053        /**
054         * Get the opcode of this instruction.
055         *
056         * @return opcode
057         */
058        public byte getOpcode() {
059            return _code[0];
060        }
061    
062        /**
063         * Get the length bytecode for this instruction, padded for the specified program counter value.
064         *
065         * @param pc PC for padding
066         *
067         * @return bytecode length
068         */
069        public int getBytecodeLength(int pc) {
070            return Opcode.getInstrSize(_code, 0, 0);
071        }
072    
073        /**
074         * Make a new generic instruction from the bytecode stating at pc, padded using paddingPC, and use the line number
075         * table for branches.
076         *
077         * @param bytecode  bytecode
078         * @param pc        starting index in bytecode
079         * @param paddingPC PC for padding
080         * @param lnt       line number table for branches
081         */
082        public GenericInstruction(byte[] bytecode, int pc, int paddingPC, LineNumberTable lnt) {
083            _code = new byte[Opcode.getInstrSize(bytecode, pc, paddingPC)];
084            System.arraycopy(bytecode, pc, _code, 0, _code.length);
085        }
086    
087        /**
088         * Get the bytecode for this instruction, padded for the specified program counter value, with branch targets
089         * according to the specified line number table
090         *
091         * @param pc  PC for padding
092         * @param lnt line number table for branches
093         *
094         * @return bytecode
095         */
096        public byte[] getBytecode(int pc, LineNumberTable lnt) {
097            return getBytecode();
098        }
099    
100        /**
101         * Get the bytecode for this instruction.
102         *
103         * @return bytecode
104         */
105        public byte[] getBytecode() {
106            byte[] b = new byte[_code.length];
107            System.arraycopy(_code, 0, b, 0, _code.length);
108            return b;
109        }
110    
111        /**
112         * Return true of this instruction and the other object are equal.
113         *
114         * @param o other object
115         *
116         * @return true if equal
117         */
118        public boolean equals(Object o) {
119            if (this == o) {
120                return true;
121            }
122            if (!(o instanceof GenericInstruction)) {
123                return false;
124            }
125    
126            final GenericInstruction genericInstruction = (GenericInstruction)o;
127    
128            if (!Arrays.equals(_code, genericInstruction._code)) {
129                return false;
130            }
131    
132            return true;
133        }
134    
135        /**
136         * Return hash code.
137         *
138         * @return hash code
139         */
140        public int hashCode() {
141            return _code[0];
142        }
143    
144        /**
145         * Return an array of target indices.
146         *
147         * @return array of target indices.
148         */
149        public int[] getBranchTargets() {
150            return new int[0];
151        }
152    
153        /**
154         * Set the branch target indices.
155         *
156         * @param branchTargets array of target indices
157         */
158        public void setBranchTargets(int[] branchTargets) {
159            if (branchTargets.length != 0) {
160                throw new IllegalArgumentException("Generic instruction cannot have a target");
161            }
162        }
163    
164        /**
165         * Return instruction in human-readable form.
166         *
167         * @return string representation
168         */
169        public String toString() {
170            StringBuilder x = new StringBuilder();
171            x.append(Opcode.getOpcodeName(_code[0]));
172            x.append(" ");
173            for(int i = 1; i < _code.length; ++i) {
174                x.append(String.format("%02x", new Object[]{new Byte(_code[i])}) + " ");
175            }
176            return x.toString();
177        }
178    }
179