001    package sysModel.classFile.code.instructions;
002    
003    import sysModel.classFile.code.Opcode;
004    
005    /**
006     * Wide Java instruction.
007     *
008     * @author Mathias Ricken
009     */
010    public class WideInstruction extends GenericInstruction {
011        /**
012         * Constructor.
013         *
014         * @param code bytecode for generic instruction, excluding the WIDE opcode
015         */
016        public WideInstruction(byte[] code) {
017            super(new byte[]{Opcode.NOP});
018    
019            switch(code[0]) {
020                case Opcode.ALOAD:
021                case Opcode.DLOAD:
022                case Opcode.ILOAD:
023                case Opcode.FLOAD:
024                case Opcode.LLOAD:
025                case Opcode.ASTORE:
026                case Opcode.DSTORE:
027                case Opcode.ISTORE:
028                case Opcode.FSTORE:
029                case Opcode.LSTORE:
030                case Opcode.RET:
031                case Opcode.IINC:
032                    break;
033                default:
034                    throw new IllegalArgumentException("Illegal wide instruction");
035            }
036    
037            _code = new byte[code.length + 1];
038            _code[0] = Opcode.WIDE;
039            System.arraycopy(code, 0, _code, 1, code.length);
040        }
041    
042        /**
043         * Get the opcode of this instruction.
044         *
045         * @return opcode
046         */
047        public byte getOpcode() {
048            return Opcode.WIDE;
049        }
050    
051        /**
052         * Get the length bytecode for this instruction, padded for the specified program counter value.
053         *
054         * @param pc PC for padding
055         *
056         * @return bytecode length
057         */
058        public short getBytecodeLength(short pc) {
059            switch(_code[1]) {
060                case Opcode.ALOAD:
061                case Opcode.DLOAD:
062                case Opcode.ILOAD:
063                case Opcode.FLOAD:
064                case Opcode.LLOAD:
065                case Opcode.ASTORE:
066                case Opcode.DSTORE:
067                case Opcode.ISTORE:
068                case Opcode.FSTORE:
069                case Opcode.LSTORE:
070                case Opcode.RET:
071                    return 4;
072                case Opcode.IINC:
073                    return 6;
074                default:
075                    throw new IllegalArgumentException("Illegal wide instruction");
076            }
077        }
078    
079        /**
080         * Make a new generic instruction from the bytecode stating at pc, padded using paddingPC, and use the line number
081         * table for branches.
082         *
083         * @param bytecode  bytecode
084         * @param pc        starting index in bytecode
085         * @param paddingPC PC for padding
086         * @param lnt       line number table for branches
087         */
088        public WideInstruction(byte[] bytecode, short pc, short paddingPC, LineNumberTable lnt) {
089            super(bytecode, pc, paddingPC, lnt);
090        }
091    
092        /**
093         * Return hash code.
094         *
095         * @return hash code
096         */
097        public int hashCode() {
098            return _code[2];
099        }
100    
101        /**
102         * Set the branch target indices.
103         *
104         * @param branchTargets array of target indices
105         */
106        public void setBranchTargets(short[] branchTargets) {
107            if (0 != branchTargets.length) {
108                throw new IllegalArgumentException("Wide instruction cannot have a target");
109            }
110        }
111    
112        /**
113         * Return instruction in human-readable form.
114         *
115         * @return string representation
116         */
117        public String toString() {
118            StringBuffer x = new StringBuffer();
119            x.append(Opcode.getOpcodeName(Opcode.WIDE));
120            x.append(' ');
121            x.append(Opcode.getOpcodeName(_code[1]));
122            x.append(' ');
123            for(int i = 2; i < _code.length; ++i) {
124                x.append(String.format("%02x", new Object[]{new Byte(_code[i])})).append(' ');
125            }
126            return x.toString();
127        }
128    }