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 }