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    import edu.rice.cs.cunit.util.Types;
006    
007    /**
008     * Instruction containing a reference to the constant pool.
009     *
010     * @author Mathias
011     */
012    public class ReferenceInstruction extends GenericInstruction {
013        /**
014         * Size of the reference in bytes.
015         */
016        int _refSize;
017    
018        /**
019         * Constructor.
020         *
021         * @param opcode         invoke opcode
022         * @param constantPoolId method id in constant pool
023         */
024        public ReferenceInstruction(byte opcode, int constantPoolId) {
025            super(new byte[]{Opcode.NOP});
026    
027            assert(constantPoolId <= 0xFFFF);
028            checkOpcode(opcode);
029    
030            _code = new byte[1+_refSize];
031            _code[0] = opcode;
032            setReference(constantPoolId);
033        }
034    
035        /**
036         * Make a new generic instruction from the bytecode stating at pc, padded using paddingPC, and use the line number
037         * table for branches.
038         *
039         * @param bytecode  bytecode
040         * @param pc        starting index in bytecode
041         * @param paddingPC PC for padding
042         * @param lnt       line number table for branches
043         */
044        public ReferenceInstruction(byte[] bytecode, int pc, int paddingPC, LineNumberTable lnt) {
045            super(bytecode, pc, paddingPC, lnt);
046            checkOpcode(bytecode[pc]);
047        }
048    
049        /**
050         * Check the opcode to make sure it is a reference instruction.
051         * @param opcode opcode to check
052         */
053        private void checkOpcode(byte opcode) {
054            switch(opcode) {
055                case Opcode.INVOKESTATIC:
056                case Opcode.INVOKESPECIAL:
057                case Opcode.INVOKEVIRTUAL:
058                case Opcode.CHECKCAST:
059                case Opcode.GETFIELD:
060                case Opcode.GETSTATIC:
061                case Opcode.INSTANCEOF:
062                case Opcode.NEW:
063                case Opcode.PUTFIELD:
064                case Opcode.PUTSTATIC:
065                case Opcode.ANEWARRAY:
066                case Opcode.LDC_W:
067                case Opcode.LDC2_W:
068                    _refSize = 2;
069                    break;
070                case Opcode.LDC:
071                    _refSize = 1;
072                    break;
073                default:
074                    throw new IllegalArgumentException("Illegal reference instruction: " + Opcode.getOpcodeName(opcode));
075            }
076        }
077    
078        /**
079         * Set the constant pool id.
080         *
081         * @param constantPoolId new constant pool id
082         */
083        public void setReference(int constantPoolId) {
084            assert(constantPoolId <= 0xFFFF);
085            
086            if (_refSize==1) {
087                _code[1] = (byte)(0x00FF & constantPoolId);
088            }
089            else {
090                Types.bytesFromShort((short)(0xFFFF & constantPoolId), _code, 1);
091            }
092        }
093    
094        /**
095         * Get the constant pool id.
096         *
097         * @return constant pool id
098         */
099        public int getReference() {
100            if (_refSize==1) {
101                return _code[1] & 0xff;
102            }
103            else {
104                return Types.ushortFromBytes(_code, 1);
105            }
106        }
107    
108        /**
109         * Return a verbose string representation.
110         *
111         * @param cp constant pool
112         * @return verbose string representation
113         */
114        public String toStringVerbose(ConstantPool cp) {
115            StringBuilder x = new StringBuilder();
116            x.append(Opcode.getOpcodeName(_code[0]));
117            x.append(' ');
118            int ref = getReference();
119            assert(ref <= 0xFFFF);
120            x.append(cp.get(ref).toString());
121            x.append(' ');
122            x.append("(CP=");
123            x.append(ref);
124            x.append(") ");
125            for(int i = 1; i < _code.length; ++i) {
126                x.append(String.format("%02x ", new Object[]{new Byte(_code[i])}));
127            }
128    
129            return x.toString();
130        }
131    }