001    package sysModel.classFile.code.instructions;
002    
003    import sysModel.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 short getBytecodeLength(short pc) {
070            return (short)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, short pc, short 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(short 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            GenericInstruction genericInstruction = (GenericInstruction)o;
127            return Arrays.equals(_code, genericInstruction._code);
128    
129        }
130    
131        /**
132         * Return hash code.
133         *
134         * @return hash code
135         */
136        public int hashCode() {
137            return _code[0];
138        }
139    
140        /**
141         * Return an array of target indices.
142         *
143         * @return array of target indices.
144         */
145        public short[] getBranchTargets() {
146            return new short[0];
147        }
148    
149        /**
150         * Set the branch target indices.
151         *
152         * @param branchTargets array of target indices
153         */
154        public void setBranchTargets(short[] branchTargets) {
155            if (0 != branchTargets.length) {
156                throw new IllegalArgumentException("Generic instruction cannot have a target");
157            }
158        }
159    
160        /**
161         * Return instruction in human-readable form.
162         *
163         * @return string representation
164         */
165        public String toString() {
166            StringBuffer x = new StringBuffer();
167            x.append(Opcode.getOpcodeName(_code[0]));
168            x.append(' ');
169            for(int i = 1; i < _code.length; ++i) {
170                x.append(String.format("%02x", new Object[]{new Byte(_code[i])})).append(' ');
171            }
172            return x.toString();
173        }
174    }
175